Preliminary SILC Server 1.1 commit.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 22 Apr 2007 18:27:12 +0000 (18:27 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 22 Apr 2007 18:27:12 +0000 (18:27 +0000)
32 files changed:
CHANGES
apps/silcd/Makefile.am
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/command_reply.c
apps/silcd/command_reply.h
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/packet_receive.h
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/protocol.c [deleted file]
apps/silcd/protocol.h [deleted file]
apps/silcd/route.c
apps/silcd/route.h
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_backup.c
apps/silcd/server_backup.h
apps/silcd/server_internal.h
apps/silcd/server_query.c
apps/silcd/server_query.h
apps/silcd/server_util.c
apps/silcd/server_util.h
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
apps/silcd/serverid.c
apps/silcd/serverid.h
apps/silcd/serverincludes.h
apps/silcd/silcd.c
apps/silcd/silcd.h

diff --git a/CHANGES b/CHANGES
index 27be3f4c2f72d5026b59fe8c4761951af187744b..ef84db9e8f58b47a81451dfd7e0e7dcee6de79d7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -20,6 +20,8 @@ Sun Apr 22 21:13:28 EEST 2007  Pekka Riikonen <priikone@silcnet.org>
        * Added silc_net_get_error_string, silc_net_listener_get_ip and
          silc_net_listener_get_hostname to lib/silcutil/silcnet.[ch].
 
+       *
+
 Tue Apr 10 15:55:42 CEST 2007  Jochen Eisinger <coffee@silcnet.org>
 
        * Add option --enable-silc-plugin.  Affected files are
index 0352ea8729b15aef7dc618bea0f9931ac142a9c0..6dcf4b979f7846498f3877d819dab4d7b9487c79 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  Copyright (C) 2000 - 2005 Pekka Riikonen
+#  Copyright (C) 2000 - 2007 Pekka Riikonen
 #
 #  This program is free software; you can redistribute it and/or modify
 #  it under the terms of the GNU General Public License as published by
@@ -20,21 +20,20 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 sbin_PROGRAMS = silcd
 
 silcd_SOURCES = \
-       protocol.c \
+       serverconfig.c \
+       silcd.c \
+       server_version.c \
+       serverid.c \
        route.c \
+       idlist.c \
+       server_query.c \
+       server.c \
        packet_send.c \
        packet_receive.c \
-       idlist.c \
        command.c \
        command_reply.c \
-       silcd.c \
-       server.c \
        server_util.c \
-       server_backup.c \
-       serverconfig.c \
-       server_query.c \
-       serverid.c \
-       server_version.c
+       server_backup.c
 
 LIBS = $(SILC_COMMON_LIBS)
 LDADD =
index fce57cfd6b9035b898aadf9fd0d2925ccf7d025a..ddccf1988aaa6758a1de49ad4fabc0f1aa7abdc7 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 #include "server_internal.h"
 
 static int silc_server_is_registered(SilcServer server,
-                                    SilcSocketConnection sock,
+                                    SilcPacketStream sock,
                                     SilcServerCommandContext cmd,
                                     SilcCommand command);
 static void
@@ -126,11 +126,11 @@ do {                                                                           \
    usually cannot send commands hence the check. */
 
 static int silc_server_is_registered(SilcServer server,
-                                    SilcSocketConnection sock,
+                                    SilcPacketStream sock,
                                     SilcServerCommandContext cmd,
                                     SilcCommand command)
 {
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
+  SilcIDListData idata = silc_packet_get_context(sock);
 
   if (!idata)
     return FALSE;
@@ -155,7 +155,7 @@ typedef struct {
 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
 {
   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
-  SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(timeout->ctx->sock);
 
   if (!client) {
     SILC_LOG_DEBUG(("Client entry is invalid"));
@@ -189,32 +189,32 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
 /* Processes received command packet. */
 
 void silc_server_command_process(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
+                                SilcPacketStream sock,
+                                SilcPacket packet)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcServerCommandContext ctx;
   SilcServerCommand *cmd;
   SilcCommand command;
 
+  if (!idata)
+    return;
+
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
   ctx->server = server;
-  ctx->sock = silc_socket_dup(sock);
-  ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
+  ctx->sock = sock;
+  ctx->packet = packet; /* Save original packet */
+  silc_packet_stream_ref(sock);
 
   /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(packet->buffer->data,
-                                           packet->buffer->len);
+  ctx->payload = silc_command_payload_parse(packet->buffer.data,
+                                           silc_buffer_len(&packet->buffer));
   if (!ctx->payload) {
-    SILC_LOG_ERROR(("Bad command payload, dropped (%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")));
-    silc_packet_context_free(packet);
-    silc_socket_free(ctx->sock);
+    SILC_LOG_ERROR(("Bad command payload"));
+    silc_packet_free(packet);
+    silc_packet_stream_unref(ctx->sock);
     silc_free(ctx);
     return;
   }
@@ -230,7 +230,9 @@ void silc_server_command_process(SilcServer server,
     SILC_LOG_DEBUG(("Unknown command %d", command));
     silc_server_command_send_status_reply(ctx, command,
                                          SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
-    silc_server_command_free(ctx);
+    silc_packet_free(packet);
+    silc_packet_stream_unref(ctx->sock);
+    silc_free(ctx);
     return;
   }
 
@@ -238,17 +240,11 @@ void silc_server_command_process(SilcServer server,
      executed with zero (0) timeout but if client is sending command more
      frequently than once in 2 seconds, then the timeout may be 0 to 2
      seconds. */
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    SilcClientEntry client = (SilcClientEntry)sock->user_data;
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    SilcClientEntry client = silc_packet_get_context(sock);
     SilcServerCommandTimeout timeout;
     int fast;
 
-    if (!client) {
-      SILC_LOG_DEBUG(("Client entry is invalid"));
-      silc_server_command_free(ctx);
-      return;
-    }
-
     timeout = silc_calloc(1, sizeof(*timeout));
     timeout->ctx = ctx;
     timeout->cmd = cmd;
@@ -266,16 +262,16 @@ void silc_server_command_process(SilcServer server,
 
     if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
                  (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
-      silc_schedule_task_add(server->schedule, sock->sock,
-                            silc_server_command_process_timeout, timeout,
-                            (client->fast_command < 3 ? 0 :
-                             2 - (time(NULL) - client->last_command)),
-                            (client->fast_command < 3 ? 200000 : 0),
-                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(
+                           server->schedule,
+                           silc_server_command_process_timeout, timeout,
+                           (client->fast_command < 3 ? 0 :
+                            2 - (time(NULL) - client->last_command)),
+                           (client->fast_command < 3 ? 200000 : 0));
     else
-      silc_schedule_task_add(server->schedule, sock->sock,
-                            silc_server_command_process_timeout, timeout,
-                            0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_command_process_timeout,
+                                    timeout, 0, 1);
     return;
   }
 
@@ -313,9 +309,9 @@ void silc_server_command_free(SilcServerCommandContext ctx)
     if (ctx->payload)
       silc_command_payload_free(ctx->payload);
     if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
+      silc_packet_free(ctx->packet);
     if (ctx->sock)
-      silc_socket_free(ctx->sock); /* Decrease reference counter */
+      silc_packet_stream_unref(ctx->sock);
     silc_free(ctx);
   }
 }
@@ -361,7 +357,8 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
                                         SILC_COMMAND_RESERVED,
                                         SILC_STATUS_ERR_TIMEDOUT, 0,
                                         reply->ident, 0);
-  cmdr->payload = silc_command_payload_parse(tmpreply->data, tmpreply->len);
+  cmdr->payload = silc_command_payload_parse(tmpreply->data,
+                                            silc_buffer_len(tmpreply));
   silc_buffer_free(tmpreply);
 
   /* Call all callbacks. Same as SILC_SERVER_PENDING_EXEC macro. */
@@ -382,7 +379,7 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
    specified command, ident, callback and context this function has no
    effect. */
 
-bool silc_server_command_pending(SilcServer server,
+SilcBool silc_server_command_pending(SilcServer server,
                                 SilcCommand reply_cmd,
                                 SilcUInt16 ident,
                                 SilcCommandCb callback,
@@ -395,7 +392,7 @@ bool silc_server_command_pending(SilcServer server,
 /* Same as silc_server_command_pending with specific timeout for pending
    commands.  If the `timeout' is zero default timeout is used. */
 
-bool silc_server_command_pending_timed(SilcServer server,
+SilcBool silc_server_command_pending_timed(SilcServer server,
                                       SilcCommand reply_cmd,
                                       SilcUInt16 ident,
                                       SilcCommandCb callback,
@@ -420,10 +417,9 @@ bool silc_server_command_pending_timed(SilcServer server,
   reply->context = context;
   reply->callback = callback;
   reply->timeout =
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_command_pending_timeout, reply,
-                          timeout ? timeout : 12, 0,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_command_pending_timeout, reply,
+                                  timeout ? timeout : 12, 0);
   silc_dlist_add(server->pending_commands, reply);
 
   return TRUE;
@@ -500,7 +496,7 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
                                         0);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0,
-                         buffer->data, buffer->len, FALSE);
+                         buffer->data, silc_buffer_len(buffer));
   silc_buffer_free(buffer);
 }
 
@@ -529,7 +525,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                         1, arg_type, arg, arg_len);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0,
-                         buffer->data, buffer->len, FALSE);
+                         buffer->data, silc_buffer_len(buffer));
   silc_buffer_free(buffer);
 }
 
@@ -559,7 +555,7 @@ silc_server_command_send_status_data2(SilcServerCommandContext cmd,
                                         arg_type2, arg2, arg_len2);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0,
-                         buffer->data, buffer->len, FALSE);
+                         buffer->data, silc_buffer_len(buffer));
   silc_buffer_free(buffer);
 }
 
@@ -589,7 +585,7 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
     buffer = silc_command_payload_encode_payload(cmdr->payload);
     silc_server_packet_send(cmd->server, cmd->sock,
                            SILC_PACKET_COMMAND_REPLY, 0,
-                           buffer->data, buffer->len, FALSE);
+                           buffer->data, silc_buffer_len(buffer));
     silc_buffer_free(buffer);
     return TRUE;
   }
@@ -634,7 +630,7 @@ SILC_SERVER_CMD_FUNC(identify)
 SILC_SERVER_CMD_FUNC(nick)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcServer server = cmd->server;
   SilcBuffer nidp, oidp = NULL;
   SilcClientID *new_id;
@@ -642,7 +638,7 @@ SILC_SERVER_CMD_FUNC(nick)
   unsigned char *nick, *nickc = NULL;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
@@ -704,7 +700,7 @@ SILC_SERVER_CMD_FUNC(nick)
   oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Remove old cache entry */
-  silc_idcache_del_by_context(server->local_list->clients, client);
+  silc_idcache_del_by_context(server->local_list->clients, client, NULL);
 
   silc_free(client->id);
   client->id = new_id;
@@ -714,15 +710,15 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Update client cache */
   silc_idcache_add(server->local_list->clients, nickc,
-                  client->id, (void *)client, 0, NULL);
+                  client->id, (void *)client);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Send NICK_CHANGE notify to the client's channels */
   silc_server_send_notify_on_channels(server, NULL, client,
                                      SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
-                                     oidp->data, oidp->len,
-                                     nidp->data, nidp->len,
+                                     oidp->data, silc_buffer_len(oidp),
+                                     nidp->data, silc_buffer_len(nidp),
                                      client->nickname,
                                      strlen(client->nickname));
 
@@ -736,7 +732,7 @@ SILC_SERVER_CMD_FUNC(nick)
   silc_server_send_command_reply(cmd->server, cmd->sock,
                                 SILC_COMMAND_NICK,
                                 SILC_STATUS_OK, 0, ident, 2,
-                                2, nidp->data, nidp->len,
+                                2, nidp->data, silc_buffer_len(nidp),
                                 3, nick, nick_len);
   silc_buffer_free(nidp);
   if (oidp)
@@ -813,7 +809,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     /* Send the reply */
     silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_LIST,
                                   status, 0, ident, 4,
-                                  2, idp->data, idp->len,
+                                  2, idp->data, silc_buffer_len(idp),
                                   3, entry->channel_name,
                                   strlen(entry->channel_name),
                                   4, topic, topic ? strlen(topic) : 0,
@@ -847,7 +843,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     /* Send the reply */
     silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_LIST,
                                   status, 0, ident, 4,
-                                  2, idp->data, idp->len,
+                                  2, idp->data, silc_buffer_len(idp),
                                   3, entry->channel_name,
                                   strlen(entry->channel_name),
                                   4, topic, topic ? strlen(topic) : 0,
@@ -864,9 +860,7 @@ SILC_SERVER_CMD_FUNC(list)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcChannelID *channel_id = NULL;
-  unsigned char *tmp;
-  SilcUInt32 tmp_len;
+  SilcID id;
   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
   SilcUInt32 lch_count = 0, gch_count = 0;
 
@@ -887,7 +881,7 @@ SILC_SERVER_CMD_FUNC(list)
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, cmd->packet->flags,
-                           tmpbuf->data, tmpbuf->len, TRUE);
+                           tmpbuf->data, silc_buffer_len(tmpbuf));
 
     /* Reprocess this packet after received reply from router */
     silc_server_command_pending(server, SILC_COMMAND_LIST,
@@ -901,22 +895,18 @@ SILC_SERVER_CMD_FUNC(list)
   }
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (tmp) {
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
-                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-      goto out;
-    }
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
+    goto out;
   }
 
   /* Get the channels from local list */
-  lchannels = silc_idlist_get_channels(server->local_list, channel_id,
+  lchannels = silc_idlist_get_channels(server->local_list, SILC_ID_GET_ID(id),
                                       &lch_count);
 
   /* Get the channels from global list */
-  gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+  gchannels = silc_idlist_get_channels(server->global_list, SILC_ID_GET_ID(id),
                                       &gch_count);
 
   /* Send the reply */
@@ -937,8 +927,8 @@ SILC_SERVER_CMD_FUNC(topic)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcChannelID *channel_id;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
+  SilcID id;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer idp;
@@ -946,7 +936,7 @@ SILC_SERVER_CMD_FUNC(topic)
   SilcUInt32 argc, tmp_len;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
@@ -954,14 +944,7 @@ SILC_SERVER_CMD_FUNC(topic)
   argc = silc_argument_get_arg_num(cmd->args);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
@@ -969,11 +952,12 @@ SILC_SERVER_CMD_FUNC(topic)
 
   /* Check whether the channel exists */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, tmp_len);
@@ -983,22 +967,19 @@ SILC_SERVER_CMD_FUNC(topic)
 
   if (argc > 1) {
     /* Get the topic */
-    tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+    tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                            0);
       goto out;
     }
-
-    if (strlen(tmp) > 256) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
-                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
-                                           0);
-      goto out;
+    if (tmp_len > 256) {
+      tmp_len = 256;
+      tmp[tmp_len - 1] = '\0';
     }
 
-    if (!silc_utf8_valid(tmp, strlen(tmp))) {
+    if (!silc_utf8_valid(tmp, tmp_len)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                            0);
@@ -1039,7 +1020,7 @@ SILC_SERVER_CMD_FUNC(topic)
       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_TOPIC_SET, 2,
-                                        idp->data, idp->len,
+                                        idp->data, silc_buffer_len(idp),
                                         channel->topic,
                                         strlen(channel->topic));
       silc_buffer_free(idp);
@@ -1047,15 +1028,14 @@ SILC_SERVER_CMD_FUNC(topic)
   }
 
   /* Send the topic to client as reply packet */
-  idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
   silc_server_send_command_reply(cmd->server, cmd->sock, SILC_COMMAND_TOPIC,
                                 SILC_STATUS_OK, 0, ident, 2,
-                                2, idp->data, idp->len,
+                                2, idp->data, silc_buffer_len(idp),
                                 3, channel->topic,
                                 channel->topic ?
                                 strlen(channel->topic) : 0);
   silc_buffer_free(idp);
-  silc_free(channel_id);
 
  out:
   silc_server_command_free(cmd);
@@ -1068,12 +1048,11 @@ SILC_SERVER_CMD_FUNC(invite)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcSocketConnection sock = cmd->sock, dest_sock;
+  SilcPacketStream sock = cmd->sock, dest_sock;
   SilcChannelClientEntry chl;
   SilcClientEntry sender, dest;
-  SilcClientID *dest_id = NULL;
   SilcChannelEntry channel;
-  SilcChannelID *channel_id = NULL;
+  SilcID id, id2;
   SilcIDListData idata;
   SilcArgumentPayload args;
   SilcHashTableList htl;
@@ -1086,14 +1065,7 @@ SILC_SERVER_CMD_FUNC(invite)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  channel_id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
@@ -1101,11 +1073,12 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Get the channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, len);
@@ -1114,8 +1087,9 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Check whether the sender of this command is on the channel. */
-  sender = (SilcClientEntry)sock->user_data;
+  sender = silc_packet_get_context(sock);
   if (!sender || !silc_server_client_on_channel(sender, channel, &chl)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp, len);
@@ -1127,6 +1101,7 @@ SILC_SERVER_CMD_FUNC(invite)
   if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                         0, 2, tmp, len);
@@ -1134,21 +1109,15 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Get destination client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
-  if (tmp) {
-    bool resolve;
-
-    dest_id = silc_id_payload_parse_id(tmp, len, NULL);
-    if (!dest_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                           SILC_STATUS_ERR_NO_CLIENT_ID, 0);
-      goto out;
-    }
+  if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id2, NULL)) {
+    SilcBool resolve;
 
     /* Get the client entry */
-    dest = silc_server_query_client(server, dest_id, FALSE, &resolve);
+    dest = silc_server_query_client(server, SILC_ID_GET_ID(id2),
+                                   FALSE, &resolve);
     if (!dest) {
       if (server->server_type != SILC_SERVER || !resolve || cmd->pending) {
+       tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
        silc_server_command_send_status_data(
                                        cmd, SILC_COMMAND_INVITE,
                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
@@ -1168,6 +1137,7 @@ SILC_SERVER_CMD_FUNC(invite)
 
     /* Check whether the requested client is already on the channel. */
     if (silc_server_client_on_channel(dest, channel, NULL)) {
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
       atype = silc_argument_get_arg_type(cmd->args, 1, &len2);
       silc_server_command_send_status_data2(cmd, SILC_COMMAND_INVITE,
                                            SILC_STATUS_ERR_USER_ON_CHANNEL,
@@ -1177,9 +1147,11 @@ SILC_SERVER_CMD_FUNC(invite)
     }
 
     /* Get route to the client */
-    dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id,
+    dest_sock = silc_server_get_client_route(server, NULL, 0,
+                                            SILC_ID_GET_ID(id2),
                                             &idata, NULL);
     if (!dest_sock) {
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
                                           0, 2, tmp, len);
@@ -1196,6 +1168,7 @@ SILC_SERVER_CMD_FUNC(invite)
                              silc_server_inviteban_destruct, channel, TRUE);
 
     /* Check if the ID is in the list already */
+    tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
     silc_hash_table_list(channel->invite_list, &htl);
     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2)) {
       if (type == 3 && !memcmp(tmp2->data, tmp, len)) {
@@ -1215,15 +1188,15 @@ SILC_SERVER_CMD_FUNC(invite)
     if (!(dest->mode & SILC_UMODE_BLOCK_INVITE)) {
       /* Send notify to the client that is invited to the channel */
       SilcBuffer idp, idp2;
-      idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+      idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
-      silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
-                                  SILC_ID_CLIENT,
+      silc_server_send_notify_dest(server, dest_sock, FALSE,
+                                  SILC_ID_GET_ID(id2), SILC_ID_CLIENT,
                                   SILC_NOTIFY_TYPE_INVITE, 3,
-                                  idp->data, idp->len,
+                                  idp->data, silc_buffer_len(idp),
                                   channel->channel_name,
                                   strlen(channel->channel_name),
-                                  idp2->data, idp2->len);
+                                  idp2->data, silc_buffer_len(idp2));
       silc_buffer_free(idp);
       silc_buffer_free(idp2);
     }
@@ -1286,8 +1259,8 @@ SILC_SERVER_CMD_FUNC(invite)
                       SILC_STR_END);
     silc_hash_table_list(channel->invite_list, &htl);
     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
-      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
-                                             type);
+      list = silc_argument_payload_encode_one(list, tmp2->data,
+                                             silc_buffer_len(tmp2), type);
     silc_hash_table_list_reset(&htl);
   }
 
@@ -1298,17 +1271,17 @@ SILC_SERVER_CMD_FUNC(invite)
     /* Send to local servers if we are router */
     if (server->server_type == SILC_ROUTER) {
       SilcBuffer idp, idp2;
-      idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+      idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
                                          SILC_NOTIFY_TYPE_INVITE, 5,
-                                        idp->data, idp->len,
+                                        idp->data, silc_buffer_len(idp),
                                         channel->channel_name,
                                         strlen(channel->channel_name),
-                                        idp2->data, idp2->len,
+                                        idp2->data, silc_buffer_len(idp2),
                                         atype, 1,
                                         tmp ? alist.data : NULL,
-                                        tmp ? alist.len : 0);
+                                        tmp ? silc_buffer_len(&alist) : 0);
       silc_buffer_free(idp);
       silc_buffer_free(idp2);
     }
@@ -1336,17 +1309,15 @@ SILC_SERVER_CMD_FUNC(invite)
                                 2, tmp, len,
                                 3, type && list ?
                                 list->data : NULL,
-                                type && list ? list->len : 0);
+                                type && list ? silc_buffer_len(list) : 0);
   silc_buffer_free(list);
 
  out:
-  silc_free(dest_id);
-  silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
 typedef struct {
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   char *signoff;
 } *QuitInternal;
 
@@ -1357,20 +1328,17 @@ SILC_TASK_CALLBACK(silc_server_command_quit_cb)
 {
   SilcServer server = app_context;
   QuitInternal q = (QuitInternal)context;
+  SilcClientEntry client = silc_packet_get_context(q->sock);
 
-  if (q->sock->user_data) {
+  if (client) {
     /* Free all client specific data, such as client entry and entires
        on channels this client may be on. */
-    silc_server_free_client_data(server, q->sock, q->sock->user_data,
+    silc_server_free_client_data(server, q->sock, client,
                                 TRUE, q->signoff);
-    q->sock->user_data = NULL;
+    silc_packet_set_context(q->sock, NULL);
   }
 
-  if (!SILC_IS_DISCONNECTED(q->sock))
-    /* Close the connection on our side */
-    silc_server_close_connection(server, q->sock);
-
-  silc_socket_free(q->sock);
+  silc_packet_stream_unref(q->sock);
   silc_free(q->signoff);
   silc_free(q);
 }
@@ -1381,14 +1349,15 @@ SILC_SERVER_CMD_FUNC(quit)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcSocketConnection sock = cmd->sock;
+  SilcPacketStream sock = cmd->sock;
+  SilcClientEntry client = silc_packet_get_context(sock);
   QuitInternal q;
   unsigned char *tmp = NULL;
   SilcUInt32 len = 0;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (client->data.conn_type != SILC_CONN_CLIENT)
     goto out;
 
   /* Get message */
@@ -1397,13 +1366,14 @@ SILC_SERVER_CMD_FUNC(quit)
     tmp = NULL;
 
   q = silc_calloc(1, sizeof(*q));
-  q->sock = silc_socket_dup(sock);
+  q->sock = sock;
   q->signoff = tmp ? strdup(tmp) : NULL;
+  silc_packet_stream_ref(q->sock);
 
   /* We quit the connection with little timeout */
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_command_quit_cb, (void *)q,
-                        0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_command_quit_cb, (void *)q,
+                                0, 200000);
 
  out:
   silc_server_command_free(cmd);
@@ -1416,15 +1386,15 @@ SILC_SERVER_CMD_FUNC(kill)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcClientEntry remote_client;
-  SilcClientID *client_id = NULL;
+  SilcID id;
   unsigned char *tmp, *comment, *auth;
   SilcUInt32 tmp_len, tmp_len2, auth_len;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 3);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   /* Get authentication payload if present */
@@ -1449,28 +1419,22 @@ SILC_SERVER_CMD_FUNC(kill)
   }
 
   /* Get the client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
-                                         0);
-    goto out;
-  }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
-                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                        0, 2, tmp, tmp_len);
+                                         SILC_STATUS_ERR_NO_CLIENT_ID, 0);
     goto out;
   }
 
   /* Get the client entry */
   remote_client = silc_idlist_find_client_by_id(server->local_list,
-                                               client_id, TRUE, NULL);
+                                               SILC_ID_GET_ID(id),
+                                               TRUE, NULL);
   if (!remote_client) {
     remote_client = silc_idlist_find_client_by_id(server->global_list,
-                                                 client_id, TRUE, NULL);
+                                                 SILC_ID_GET_ID(id),
+                                                 TRUE, NULL);
     if (!remote_client) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
                                           0, 2, tmp, tmp_len);
@@ -1488,7 +1452,7 @@ SILC_SERVER_CMD_FUNC(kill)
   /* If authentication data is provided then verify that killing is
      actually allowed */
   if (auth && auth_len) {
-    SilcSocketConnection sock;
+    SilcPacketStream sock;
 
     if (!SILC_IS_LOCAL(remote_client) || !remote_client->data.public_key) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
@@ -1508,6 +1472,7 @@ SILC_SERVER_CMD_FUNC(kill)
     }
 
     /* Send reply to the sender */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
                                         SILC_STATUS_OK, 0,
                                         2, tmp, tmp_len);
@@ -1525,6 +1490,7 @@ SILC_SERVER_CMD_FUNC(kill)
     /* Router operator killing */
 
     /* Send reply to the sender */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
                                         SILC_STATUS_OK, 0,
                                         2, tmp, tmp_len);
@@ -1540,7 +1506,6 @@ SILC_SERVER_CMD_FUNC(kill)
   }
 
  out:
-  silc_free(client_id);
   silc_server_command_free(cmd);
 }
 
@@ -1558,7 +1523,7 @@ SILC_SERVER_CMD_FUNC(info)
   char *dest_server = NULL, *server_info = NULL, *server_name;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   SilcServerEntry entry = NULL;
-  SilcServerID *server_id = NULL;
+  SilcID id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
 
@@ -1576,24 +1541,15 @@ SILC_SERVER_CMD_FUNC(info)
   }
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (tmp) {
-    server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!server_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
-                                           SILC_STATUS_ERR_NO_SERVER_ID, 0);
-      goto out;
-    }
-  }
-
-  if (server_id) {
+  if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
     /* Check whether we have this server cached */
     entry = silc_idlist_find_server_by_id(server->local_list,
-                                         server_id, TRUE, NULL);
+                                         SILC_ID_GET_ID(id), TRUE, NULL);
     if (!entry) {
       entry = silc_idlist_find_server_by_id(server->global_list,
-                                           server_id, TRUE, NULL);
+                                           SILC_ID_GET_ID(id), TRUE, NULL);
       if (!entry && server->server_type != SILC_SERVER) {
+       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
                                             SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
                                             0, 2, tmp, tmp_len);
@@ -1602,12 +1558,7 @@ SILC_SERVER_CMD_FUNC(info)
     }
   }
 
-  /* Some buggy servers has sent request to router about themselves. */
-  if (server->server_type != SILC_SERVER && cmd->sock->user_data == entry)
-    goto out;
-
-  if ((!dest_server && !server_id && !entry) || (entry &&
-                                                entry == server->id_entry) ||
+  if ((!dest_server && !entry) || (entry && entry == server->id_entry) ||
       (dest_server && !cmd->pending &&
        !memcmp(dest_server, server->server_name, strlen(dest_server)))) {
     /* Send our reply */
@@ -1649,7 +1600,7 @@ SILC_SERVER_CMD_FUNC(info)
 
       silc_server_packet_send(server, entry->connection,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_INFO,
@@ -1676,7 +1627,7 @@ SILC_SERVER_CMD_FUNC(info)
 
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_INFO,
@@ -1690,8 +1641,6 @@ SILC_SERVER_CMD_FUNC(info)
     }
   }
 
-  silc_free(server_id);
-
   if (!entry) {
     if (dest_server) {
       silc_free(dest_server);
@@ -1713,7 +1662,7 @@ SILC_SERVER_CMD_FUNC(info)
   /* Send the reply */
   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_INFO,
                                 SILC_STATUS_OK, 0, ident, 3,
-                                2, idp->data, idp->len,
+                                2, idp->data, silc_buffer_len(idp),
                                 3, server_name,
                                 strlen(server_name),
                                 4, server_info,
@@ -1734,27 +1683,24 @@ SILC_SERVER_CMD_FUNC(ping)
   SilcServer server = cmd->server;
   SilcUInt32 tmp_len;
   unsigned char *tmp;
-  SilcServerID *server_id = NULL;
+  SilcID id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PING, cmd, 1, 1);
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                          0);
     goto out;
   }
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
-    goto out;
 
-  if (SILC_ID_SERVER_COMPARE(server_id, server->id)) {
+  if (SILC_ID_SERVER_COMPARE(SILC_ID_GET_ID(id), server->id)) {
     /* Send our reply */
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_OK, 0);
   } else {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_PING,
                                         SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
                                         2, tmp, tmp_len);
@@ -1762,7 +1708,6 @@ SILC_SERVER_CMD_FUNC(ping)
   }
 
  out:
-  silc_free(server_id);
   silc_server_command_free(cmd);
 }
 
@@ -1772,7 +1717,7 @@ SILC_SERVER_CMD_FUNC(stats)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcServerID *server_id;
+  SilcID id;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   SilcBuffer packet, stats;
@@ -1782,25 +1727,20 @@ SILC_SERVER_CMD_FUNC(stats)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_STATS, cmd, 1, 1);
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_STATS,
                                          SILC_STATUS_ERR_NO_SERVER_ID, 0);
     goto out;
   }
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
-    goto out;
 
   /* The ID must be ours */
-  if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) {
+  if (!SILC_ID_SERVER_COMPARE(server->id, SILC_ID_GET_ID(id))) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_STATS,
                                         SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
                                         2, tmp, tmp_len);
-    silc_free(server_id);
     goto out;
   }
-  silc_free(server_id);
 
   /* If we are router then just send everything we got. If we are normal
      server then we'll send this to our router to get all the latest
@@ -1817,10 +1757,11 @@ SILC_SERVER_CMD_FUNC(stats)
                                 SILC_ID_SERVER);
     packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
                                            ++server->cmd_ident, 1,
-                                           1, idp->data, idp->len);
+                                           1, idp->data,
+                                           silc_buffer_len(idp));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, 0, packet->data,
-                           packet->len, FALSE);
+                           silc_buffer_len(packet));
 
     /* Reprocess this packet after received reply from router */
     silc_server_command_pending(server, SILC_COMMAND_STATS,
@@ -1855,10 +1796,11 @@ SILC_SERVER_CMD_FUNC(stats)
                     SILC_STR_UI_INT(server->stat.router_ops),
                     SILC_STR_END);
 
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_STATS,
                                 SILC_STATUS_OK, 0, ident, 2,
                                 2, tmp, tmp_len,
-                                3, stats->data, stats->len);
+                                3, stats->data, silc_buffer_len(stats));
   silc_buffer_free(stats);
 
  out:
@@ -1873,15 +1815,16 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcServerCommandContext cmd,
                                             SilcChannelEntry channel,
                                             SilcClientID *client_id,
-                                            bool created,
-                                            bool create_key,
+                                            SilcBool created,
+                                            SilcBool create_key,
                                             SilcUInt32 umode,
                                             const unsigned char *auth,
                                             SilcUInt32 auth_len,
                                             const unsigned char *cauth,
                                             SilcUInt32 cauth_len)
 {
-  SilcSocketConnection sock = cmd->sock;
+  SilcPacketStream sock = cmd->sock;
+  SilcIDListData idata = silc_packet_get_context(sock);
   unsigned char *tmp;
   SilcUInt32 tmp_len, user_count;
   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4], ulimit[4];
@@ -1891,19 +1834,21 @@ static void silc_server_command_join_channel(SilcServer server,
   SilcBuffer user_list, mode_list, invite_list, ban_list;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   char check[512], check2[512];
-  bool founder = FALSE;
-  bool resolve;
+  SilcBool founder = FALSE;
+  SilcBool resolve;
   SilcBuffer fkey = NULL, chpklist = NULL;
-  const char *cipher;
+  const char *cipher, *hostname, *ip;
 
   SILC_LOG_DEBUG(("Joining client to channel"));
 
   if (!channel)
     return;
 
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+
   /* Get the client entry */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    client = (SilcClientEntry)sock->user_data;
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    client = (SilcClientEntry)idata;
     if (!client)
       return;
   } else {
@@ -1940,7 +1885,7 @@ static void silc_server_command_join_channel(SilcServer server,
       clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
       silc_server_send_command(server, cmd->sock,
                               SILC_COMMAND_GETKEY, ++server->cmd_ident,
-                              1, 1, clidp->data, clidp->len);
+                              1, 1, clidp->data, silc_buffer_len(clidp));
       silc_buffer_free(clidp);
       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
                                  server->cmd_ident,
@@ -2004,7 +1949,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!strchr(client->username, '@')) {
       silc_strncat(check, sizeof(check), "@", 1);
       silc_strncat(check, sizeof(check),
-                  cmd->sock->hostname, strlen(cmd->sock->hostname));
+                  hostname, strlen(hostname));
     }
 
     silc_strncat(check2, sizeof(check2),
@@ -2023,7 +1968,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!strchr(client->username, '@')) {
       silc_strncat(check2, sizeof(check2), "@", 1);
       silc_strncat(check2, sizeof(check2),
-                  cmd->sock->hostname, strlen(cmd->sock->hostname));
+                  hostname, strlen(hostname));
     }
 
     /* Check invite list if channel is invite-only channel */
@@ -2043,7 +1988,8 @@ static void silc_server_command_join_channel(SilcServer server,
        chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
                                             SILC_STATUS_ERR_NOT_INVITED, 0,
-                                            2, chidp->data, chidp->len);
+                                            2, chidp->data,
+                                            silc_buffer_len(chidp));
        silc_buffer_free(chidp);
        goto out;
       }
@@ -2067,7 +2013,8 @@ static void silc_server_command_join_channel(SilcServer server,
        silc_server_command_send_status_data(
                                      cmd, SILC_COMMAND_JOIN,
                                      SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0,
-                                     2, chidp->data, chidp->len);
+                                     2, chidp->data,
+                                     silc_buffer_len(chidp));
        silc_buffer_free(chidp);
        goto out;
       }
@@ -2080,7 +2027,8 @@ static void silc_server_command_join_channel(SilcServer server,
        chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
                                             SILC_STATUS_ERR_CHANNEL_IS_FULL,
-                                            0, 2, chidp->data, chidp->len);
+                                            0, 2, chidp->data,
+                                            silc_buffer_len(chidp));
        silc_buffer_free(chidp);
        goto out;
       }
@@ -2100,7 +2048,8 @@ static void silc_server_command_join_channel(SilcServer server,
       chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
                                           SILC_STATUS_ERR_BAD_PASSWORD, 0,
-                                          2, chidp->data, chidp->len);
+                                          2, chidp->data,
+                                          silc_buffer_len(chidp));
       silc_buffer_free(chidp);
       goto out;
     }
@@ -2126,8 +2075,10 @@ static void silc_server_command_join_channel(SilcServer server,
     chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
     silc_server_command_send_status_data2(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_USER_ON_CHANNEL, 0,
-                                         2, clidp->data, clidp->len,
-                                         3, chidp->data, chidp->len);
+                                         2, clidp->data,
+                                         silc_buffer_len(clidp),
+                                         3, chidp->data,
+                                         silc_buffer_len(chidp));
     silc_buffer_free(clidp);
     silc_buffer_free(chidp);
     goto out;
@@ -2174,18 +2125,17 @@ static void silc_server_command_join_channel(SilcServer server,
     SILC_PUT32_MSB(channel->user_limit, ulimit);
 
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
-    tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-    cipher = silc_cipher_get_name(channel->channel_key);
-    keyp = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
-                                                          SILC_ID_CHANNEL),
-                                          tmp,
+    unsigned char cid[32];
+    SilcUInt32 cid_len;
+    silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &cid_len);
+    cipher = silc_cipher_get_name(channel->send_key);
+    keyp = silc_channel_key_payload_encode(cid_len, cid,
                                           strlen(cipher), cipher,
                                           channel->key_len / 8, channel->key);
-    silc_free(tmp);
   }
 
   if (channel->founder_key)
-    fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+    fkey = silc_public_key_payload_encode(channel->founder_key);
 
   /* Encode invite list */
   invite_list = NULL;
@@ -2202,7 +2152,7 @@ static void silc_server_command_join_channel(SilcServer server,
     while (silc_hash_table_get(&htl, (void *)&tmp_len, (void *)&reply))
       invite_list = silc_argument_payload_encode_one(invite_list,
                                                     reply->data,
-                                                    reply->len, tmp_len);
+                                                    silc_buffer_len(reply), tmp_len);
     silc_hash_table_list_reset(&htl);
   }
 
@@ -2221,7 +2171,7 @@ static void silc_server_command_join_channel(SilcServer server,
     while (silc_hash_table_get(&htl, (void *)&tmp_len, (void *)&reply))
       ban_list = silc_argument_payload_encode_one(ban_list,
                                                  reply->data,
-                                                 reply->len, tmp_len);
+                                                 silc_buffer_len(reply), tmp_len);
     silc_hash_table_list_reset(&htl);
   }
 
@@ -2233,17 +2183,21 @@ static void silc_server_command_join_channel(SilcServer server,
                                         SILC_STATUS_OK, 0, ident, 16,
                                         2, channel->channel_name,
                                         strlen(channel->channel_name),
-                                        3, chidp->data, chidp->len,
-                                        4, clidp->data, clidp->len,
+                                        3, chidp->data,
+                                        silc_buffer_len(chidp),
+                                        4, clidp->data,
+                                        silc_buffer_len(clidp),
                                         5, mode, 4,
                                         6, tmp2, 4,
                                         7, keyp ? keyp->data : NULL,
-                                        keyp ? keyp->len : 0,
+                                        keyp ? silc_buffer_len(keyp) : 0,
                                         8, ban_list ? ban_list->data : NULL,
-                                        ban_list ? ban_list->len : 0,
+                                        ban_list ?
+                                        silc_buffer_len(ban_list): 0,
                                         9, invite_list ? invite_list->data :
                                         NULL,
-                                        invite_list ? invite_list->len : 0,
+                                        invite_list ?
+                                        silc_buffer_len(invite_list) : 0,
                                         10, channel->topic,
                                         channel->topic ?
                                         strlen(channel->topic) : 0,
@@ -2251,13 +2205,14 @@ static void silc_server_command_join_channel(SilcServer server,
                                         strlen(silc_hmac_get_name(channel->
                                                                   hmac)),
                                         12, tmp3, 4,
-                                        13, user_list->data, user_list->len,
+                                        13, user_list->data,
+                                        silc_buffer_len(user_list),
                                         14, mode_list->data,
-                                        mode_list->len,
+                                        silc_buffer_len(mode_list),
                                         15, fkey ? fkey->data : NULL,
-                                        fkey ? fkey->len : 0,
+                                        fkey ? silc_buffer_len(fkey) : 0,
                                         16, chpklist ? chpklist->data : NULL,
-                                        chpklist ? chpklist->len : 0,
+                                        chpklist ? silc_buffer_len(chpklist) : 0,
                                         17, (channel->mode &
                                              SILC_CHANNEL_MODE_ULIMIT ?
                                              ulimit : NULL),
@@ -2267,7 +2222,7 @@ static void silc_server_command_join_channel(SilcServer server,
 
   /* Send command reply */
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         reply->data, reply->len, FALSE);
+                         reply->data, silc_buffer_len(reply));
 
   /* Statistics */
   cmd->server->stat.commands_sent++;
@@ -2281,8 +2236,8 @@ static void silc_server_command_join_channel(SilcServer server,
   SILC_LOG_DEBUG(("Send JOIN notify to channel"));
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                     SILC_NOTIFY_TYPE_JOIN, 2,
-                                    clidp->data, clidp->len,
-                                    chidp->data, chidp->len);
+                                    clidp->data, silc_buffer_len(clidp),
+                                    chidp->data, silc_buffer_len(chidp));
 
   /* Update statistics */
   server->stat.my_chanclients++;
@@ -2299,7 +2254,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (keyp)
       /* Distribute the channel key to all backup routers. */
       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
-                             keyp->data, keyp->len, FALSE, TRUE);
+                             keyp->data, silc_buffer_len(keyp), FALSE, TRUE);
 
     /* If client became founder by providing correct founder auth data
        notify the mode change to the channel. */
@@ -2308,10 +2263,12 @@ static void silc_server_command_join_channel(SilcServer server,
       SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
-                                        clidp->data, clidp->len,
-                                        mode, 4, clidp->data, clidp->len,
+                                        clidp->data,
+                                        silc_buffer_len(clidp),
+                                        mode, 4, clidp->data,
+                                        silc_buffer_len(clidp),
                                         fkey ? fkey->data : NULL,
-                                        fkey ? fkey->len : 0);
+                                        fkey ? silc_buffer_len(fkey) : 0);
     }
   }
 
@@ -2346,13 +2303,14 @@ SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   unsigned char *auth, *cauth;
   SilcUInt32 tmp_len, auth_len, cauth_len;
   char *tmp, *channel_name, *channel_namec = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
   SilcUInt32 umode = 0;
-  bool created = FALSE, create_key = TRUE;
-  SilcClientID *client_id;
+  SilcBool created = FALSE, create_key = TRUE;
+  SilcID id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 7);
 
@@ -2367,7 +2325,7 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Truncate over long channel names */
   if (tmp_len > 256) {
-    tmp[256] = '\0';
+    tmp[tmp_len - 1] = '\0';
     tmp_len = 256;
   }
   channel_name = tmp;
@@ -2383,20 +2341,13 @@ SILC_SERVER_CMD_FUNC(join)
   }
 
   /* Get Client ID of the client who is joining to the channel */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_NO_CLIENT_ID,
                                          0);
     goto out;
   }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
-                                        SILC_STATUS_ERR_BAD_CLIENT_ID, 0,
-                                        2, tmp, tmp_len);
-    goto out;
-  }
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
 
   /* Get cipher, hmac name and auth payload */
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
@@ -2408,8 +2359,8 @@ SILC_SERVER_CMD_FUNC(join)
   channel = silc_idlist_find_channel_by_name(server->local_list,
                                             channel_namec, NULL);
 
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    SilcClientEntry entry = (SilcClientEntry)idata;
     if (!entry) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
@@ -2429,9 +2380,6 @@ SILC_SERVER_CMD_FUNC(join)
     }
 #endif /* SILC_DIST_INPLACE */
 
-    silc_free(client_id);
-    client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
-
     if (!channel ||
        (channel->disabled && server->server_type != SILC_ROUTER)) {
       /* Channel not found or not valid */
@@ -2447,7 +2395,6 @@ SILC_SERVER_CMD_FUNC(join)
                                  cmd, SILC_COMMAND_JOIN,
                                  SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
                                  0, 2, cipher, strlen(cipher));
-           silc_free(client_id);
            goto out;
          }
 
@@ -2468,10 +2415,8 @@ SILC_SERVER_CMD_FUNC(join)
          /* If this is pending command callback then we've resolved
             it and it didn't work, return since we've notified the
             client already in the command reply callback. */
-         if (cmd->pending) {
-           silc_free(client_id);
+         if (cmd->pending)
            goto out;
-         }
 
          /* Statistics */
          cmd->server->stat.commands_sent++;
@@ -2481,10 +2426,9 @@ SILC_SERVER_CMD_FUNC(join)
          tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
          /* Send JOIN command to our router */
-         silc_server_packet_send(server, (SilcSocketConnection)
-                                 SILC_PRIMARY_ROUTE(server),
+         silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                                  SILC_PACKET_COMMAND, cmd->packet->flags,
-                                 tmpbuf->data, tmpbuf->len, TRUE);
+                                 tmpbuf->data, silc_buffer_len(tmpbuf));
 
          /* Reprocess this packet after received reply from router */
          silc_server_command_pending(server, SILC_COMMAND_JOIN,
@@ -2494,7 +2438,6 @@ SILC_SERVER_CMD_FUNC(join)
          cmd->pending = TRUE;
           silc_command_set_ident(cmd->payload, old_ident);
          silc_buffer_free(tmpbuf);
-         silc_free(client_id);
          goto out;
        }
 
@@ -2511,7 +2454,6 @@ SILC_SERVER_CMD_FUNC(join)
                                       cmd, SILC_COMMAND_JOIN,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
                                       2, cipher, strlen(cipher));
-           silc_free(client_id);
            goto out;
          }
 
@@ -2528,11 +2470,9 @@ SILC_SERVER_CMD_FUNC(join)
       /* If the command came from router and we are normal server then
         something went wrong with the joining as the channel was not found.
         We can't do anything else but ignore this. */
-      if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
-         server->server_type != SILC_ROUTER) {
-       silc_free(client_id);
+      if (idata->conn_type == SILC_CONN_ROUTER ||
+         server->server_type != SILC_ROUTER)
        goto out;
-      }
 
       /* We are router and the channel does not seem exist so we will check
         our global list as well for the channel. */
@@ -2547,7 +2487,6 @@ SILC_SERVER_CMD_FUNC(join)
                                       cmd, SILC_COMMAND_JOIN,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
                                       2, cipher, strlen(cipher));
-         silc_free(client_id);
          goto out;
        }
 
@@ -2593,12 +2532,10 @@ SILC_SERVER_CMD_FUNC(join)
     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
 
   /* Join to the channel */
-  silc_server_command_join_channel(server, cmd, channel, client_id,
+  silc_server_command_join_channel(server, cmd, channel, SILC_ID_GET_ID(id),
                                   created, create_key, umode,
                                   auth, auth_len, cauth, cauth_len);
 
-  silc_free(client_id);
-
  out:
   silc_free(channel_namec);
   silc_server_command_free(cmd);
@@ -2651,20 +2588,20 @@ SILC_SERVER_CMD_FUNC(motd)
        /* No motd */
        silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
                                       SILC_STATUS_OK, 0, ident, 1,
-                                      2, idp->data, idp->len);
+                                      2, idp->data, silc_buffer_len(idp));
        goto out;
       }
 
       motd[motd_len] = 0;
       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
                                     SILC_STATUS_OK, 0, ident, 2,
-                                    2, idp->data, idp->len,
+                                    2, idp->data, silc_buffer_len(idp),
                                     3, motd, motd_len);
     } else {
       /* No motd */
       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
                                     SILC_STATUS_OK, 0, ident, 1,
-                                    2, idp->data, idp->len);
+                                    2, idp->data, silc_buffer_len(idp));
     }
     silc_buffer_free(idp);
   } else {
@@ -2693,7 +2630,7 @@ SILC_SERVER_CMD_FUNC(motd)
 
       silc_server_packet_send(server, entry->connection,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_MOTD,
@@ -2723,7 +2660,7 @@ SILC_SERVER_CMD_FUNC(motd)
 
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_MOTD,
@@ -2750,7 +2687,7 @@ SILC_SERVER_CMD_FUNC(motd)
     idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
     silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_MOTD,
                                   SILC_STATUS_OK, 0, ident, 2,
-                                  2, idp->data, idp->len,
+                                  2, idp->data, silc_buffer_len(idp),
                                   3, entry->motd,
                                   entry->motd ?
                                   strlen(entry->motd) : 0);
@@ -2770,13 +2707,13 @@ SILC_SERVER_CMD_FUNC(umode)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   unsigned char *tmp_mask, m[4];
   SilcUInt32 mask = 0;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  bool set_mask = FALSE;
+  SilcBool set_mask = FALSE;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 1, 2);
@@ -2847,9 +2784,9 @@ SILC_SERVER_CMD_FUNC(cmode)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcIDListData idata = (SilcIDListData)client;
-  SilcChannelID *channel_id = NULL;
+  SilcID id;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer cidp;
@@ -2857,7 +2794,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   char *cipher = NULL, *hmac = NULL, *passphrase = NULL, ulimit[4];
   SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2, chpklen;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  bool set_mask = FALSE, set_chpk = FALSE;
+  SilcBool set_mask = FALSE, set_chpk = FALSE;
   SilcPublicKey founder_key = NULL;
   SilcBuffer fkey = NULL, chpklist = NULL;
   SilcBufferStruct chpk;
@@ -2870,15 +2807,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 9);
 
   /* Get Channel ID */
-  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
-  if (!tmp_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    silc_server_command_free(cmd);
-    return;
-  }
-  channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     silc_server_command_free(cmd);
@@ -2887,15 +2816,15 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp_id, tmp_len2);
-      silc_free(channel_id);
       silc_server_command_free(cmd);
       return;
     }
@@ -2911,6 +2840,7 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp_id, tmp_len2);
@@ -2921,6 +2851,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (set_mask && !silc_server_check_cmode_rights(server, channel, chl,
                                                  mode_mask)) {
     SILC_LOG_DEBUG(("Client does not have rights to change mode"));
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
     silc_server_command_send_status_data(
                             cmd, SILC_COMMAND_CMODE,
                             (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ?
@@ -2936,18 +2867,19 @@ SILC_SERVER_CMD_FUNC(cmode)
     unsigned char m[4];
     SILC_PUT32_MSB(channel->mode, m);
     if (channel->founder_key)
-      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+      fkey = silc_public_key_payload_encode(channel->founder_key);
     if (channel->channel_pubkeys)
       chpklist = silc_server_get_channel_pk_list(server, channel,
                                                 FALSE, FALSE);
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
     silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CMODE,
                                   SILC_STATUS_OK, 0, ident, 4,
                                   2, tmp_id, tmp_len2,
                                   3, m, sizeof(m),
                                   4, fkey ? fkey->data : NULL,
-                                  fkey ? fkey->len : 0,
+                                  fkey ? silc_buffer_len(fkey) : 0,
                                   5, chpklist ? chpklist->data : NULL,
-                                  chpklist ? chpklist->len : 0);
+                                  chpklist ? silc_buffer_len(chpklist) : 0);
     goto out;
   }
 
@@ -2980,7 +2912,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                   server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
 
-      cipher = (char *)silc_cipher_get_name(channel->channel_key);
+      cipher = (char *)silc_cipher_get_name(channel->send_key);
       hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
@@ -3033,7 +2965,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
       /* Cipher to use protect the traffic */
-      SilcCipher newkey, oldkey;
+      SilcCipher send_key, receive_key, olds, oldr;
 
       /* Get cipher */
       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
@@ -3044,7 +2976,14 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Delete old cipher and allocate the new one */
-      if (!silc_cipher_alloc(cipher, &newkey)) {
+      if (!silc_cipher_alloc(cipher, &send_key)) {
+       silc_server_command_send_status_data(
+                                        cmd, SILC_COMMAND_CMODE,
+                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                        2, cipher, strlen(cipher));
+       goto out;
+      }
+      if (!silc_cipher_alloc(cipher, &receive_key)) {
        silc_server_command_send_status_data(
                                         cmd, SILC_COMMAND_CMODE,
                                         SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
@@ -3052,18 +2991,22 @@ SILC_SERVER_CMD_FUNC(cmode)
        goto out;
       }
 
-      oldkey = channel->channel_key;
-      channel->channel_key = newkey;
+      olds = channel->send_key;
+      oldr = channel->receive_key;
+      channel->send_key = send_key;
+      channel->receive_key = receive_key;
 
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0)) {
        /* We don't have new key, revert to old one */
-       channel->channel_key = oldkey;
+       channel->send_key = olds;
+       channel->receive_key = oldr;
        goto out;
       }
 
       /* Remove old channel key for good */
-      silc_cipher_free(oldkey);
+      silc_cipher_free(olds);
+      silc_cipher_free(oldr);
 
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
@@ -3075,11 +3018,20 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       /* Cipher mode is unset. Remove the cipher and revert back to
         default cipher */
-      SilcCipher newkey, oldkey;
+      SilcCipher send_key, receive_key, olds, oldr;
       cipher = channel->cipher;
 
       /* Delete old cipher and allocate default one */
-      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
+      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
+                            &send_key)) {
+       silc_server_command_send_status_data(
+                                     cmd, SILC_COMMAND_CMODE,
+                                     SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                     2, cipher, strlen(cipher));
+       goto out;
+      }
+      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
+                            &receive_key)) {
        silc_server_command_send_status_data(
                                      cmd, SILC_COMMAND_CMODE,
                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
@@ -3087,18 +3039,22 @@ SILC_SERVER_CMD_FUNC(cmode)
        goto out;
       }
 
-      oldkey = channel->channel_key;
-      channel->channel_key = newkey;
+      olds = channel->send_key;
+      oldr = channel->receive_key;
+      channel->send_key = send_key;
+      channel->receive_key = receive_key;
 
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0)) {
        /* We don't have new key, revert to old one */
-       channel->channel_key = oldkey;
+       channel->send_key = olds;
+       channel->receive_key = oldr;
        goto out;
       }
 
       /* Remove old channel key for good */
-      silc_cipher_free(oldkey);
+      silc_cipher_free(olds);
+      silc_cipher_free(oldr);
 
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
@@ -3179,7 +3135,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       founder_key = idata->public_key;
       tmp = silc_argument_get_arg_type(cmd->args, 8, &tmp_len);
       if (tmp) {
-       if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
+       if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                                SILC_STATUS_ERR_AUTH_FAILED,
                                                0);
@@ -3225,7 +3181,7 @@ SILC_SERVER_CMD_FUNC(cmode)
        goto out;
       }
 
-      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+      fkey = silc_public_key_payload_encode(channel->founder_key);
       if (!fkey) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED,
@@ -3286,14 +3242,14 @@ SILC_SERVER_CMD_FUNC(cmode)
     SILC_PUT32_MSB(channel->user_limit, ulimit);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                     SILC_NOTIFY_TYPE_CMODE_CHANGE, 8,
-                                    cidp->data, cidp->len,
+                                    cidp->data, silc_buffer_len(cidp),
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
                                     hmac, hmac ? strlen(hmac) : 0,
                                     passphrase, passphrase ?
                                     strlen(passphrase) : 0,
                                     fkey ? fkey->data : NULL,
-                                    fkey ? fkey->len : 0,
+                                    fkey ? silc_buffer_len(fkey) : 0,
                                     chpkdata ? chpkdata : NULL,
                                     chpkdata ? chpklen : 0,
                                     mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
@@ -3314,14 +3270,15 @@ SILC_SERVER_CMD_FUNC(cmode)
     chpklist = silc_server_get_channel_pk_list(server, channel, FALSE, FALSE);
 
   /* Send command reply to sender */
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_CMODE,
                                 SILC_STATUS_OK, 0, ident, 5,
                                 2, tmp_id, tmp_len2,
                                 3, tmp_mask, 4,
                                 4, fkey ? fkey->data : NULL,
-                                fkey ? fkey->len : 0,
+                                fkey ? silc_buffer_len(fkey) : 0,
                                 5, chpklist ? chpklist->data :
-                                NULL, chpklist ? chpklist->len
+                                NULL, chpklist ? silc_buffer_len(chpklist)
                                 : 0,
                                 6, (mode_mask &
                                     SILC_CHANNEL_MODE_ULIMIT ?
@@ -3335,7 +3292,6 @@ SILC_SERVER_CMD_FUNC(cmode)
   channel->mode = old_mask;
   silc_buffer_free(chpklist);
   silc_buffer_free(fkey);
-  silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
@@ -3345,9 +3301,8 @@ SILC_SERVER_CMD_FUNC(cumode)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcChannelID *channel_id = NULL;
-  SilcClientID *client_id = NULL;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
+  SilcID id, id2;
   SilcChannelEntry channel;
   SilcClientEntry target_client;
   SilcChannelClientEntry chl;
@@ -3365,14 +3320,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
   /* Get Channel ID */
-  tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
-  if (!tmp_ch_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  channel_id = silc_id_payload_parse_id(tmp_ch_id, tmp_ch_len, NULL);
-  if (!channel_id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
@@ -3380,11 +3328,12 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp_ch_id, tmp_ch_len);
@@ -3394,6 +3343,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Check whether sender is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp_ch_id, tmp_ch_len);
@@ -3412,14 +3362,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   SILC_GET32_MSB(target_mask, tmp_mask);
 
   /* Get target Client ID */
-  tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (!tmp_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CLIENT_ID, 0);
-    goto out;
-  }
-  client_id = silc_id_payload_parse_id(tmp_id, tmp_len, NULL);
-  if (!client_id) {
+  if (!silc_argument_get_decoded(cmd->args, 3, SILC_ARGUMENT_ID, &id2, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                          SILC_STATUS_ERR_NO_CLIENT_ID, 0);
     goto out;
@@ -3427,14 +3370,17 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Get target client's entry */
   target_client = silc_idlist_find_client_by_id(server->local_list,
-                                               client_id, TRUE, NULL);
+                                               SILC_ID_GET_ID(id2),
+                                               TRUE, NULL);
   if (!target_client)
     target_client = silc_idlist_find_client_by_id(server->global_list,
-                                                 client_id, TRUE, NULL);
+                                                 SILC_ID_GET_ID(id2),
+                                                 TRUE, NULL);
 
   if (target_client != client &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
+    tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                         SILC_STATUS_ERR_NOT_YOU, 0,
                                         2, tmp_ch_id, tmp_ch_len);
@@ -3444,6 +3390,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   /* Check whether target client is on the channel */
   if (target_client != client) {
     if (!silc_server_client_on_channel(target_client, channel, &chl)) {
+      tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
+      tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
       silc_server_command_send_status_data2(
                                  cmd, SILC_COMMAND_CUMODE,
                                  SILC_STATUS_ERR_USER_NOT_ON_CHANNEL, 0,
@@ -3460,6 +3408,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   /* If the target client is founder, no one else can change their mode
      but themselves. */
   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
+    tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
                                         0, 2, tmp_ch_id, tmp_ch_len);
@@ -3506,7 +3455,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
       notify = TRUE;
       founder_key = channel->founder_key;
-      fkey = silc_pkcs_public_key_payload_encode(founder_key);
+      fkey = silc_public_key_payload_encode(founder_key);
       if (!fkey) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED, 0);
@@ -3553,6 +3502,7 @@ SILC_SERVER_CMD_FUNC(cumode)
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
         silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                             0, 2, tmp_ch_id, tmp_ch_len);
@@ -3566,6 +3516,7 @@ SILC_SERVER_CMD_FUNC(cumode)
     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
         silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                             0, 2, tmp_ch_id, tmp_ch_len);
@@ -3674,16 +3625,17 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+  tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
-                                      idp->data, idp->len,
+                                      idp->data, silc_buffer_len(idp),
                                       tmp_mask, 4,
                                       tmp_id, tmp_len,
                                       fkey ? fkey->data : NULL,
-                                      fkey ? fkey->len : 0);
+                                      fkey ? silc_buffer_len(fkey) : 0);
 
     /* Set CUMODE notify type to network */
     silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
@@ -3701,8 +3653,6 @@ SILC_SERVER_CMD_FUNC(cumode)
   silc_buffer_free(idp);
 
  out:
-  silc_free(channel_id);
-  silc_free(client_id);
   silc_buffer_free(fkey);
   silc_server_command_free(cmd);
 }
@@ -3713,10 +3663,9 @@ SILC_SERVER_CMD_FUNC(kick)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcClientEntry target_client;
-  SilcChannelID *channel_id;
-  SilcClientID *client_id;
+  SilcID id, id2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer idp;
@@ -3730,27 +3679,20 @@ SILC_SERVER_CMD_FUNC(kick)
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
   }
-  channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!channel_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
-                                        SILC_STATUS_ERR_BAD_CHANNEL_ID, 0,
-                                         2, tmp, tmp_len);
-    goto out;
-  }
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->local_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, tmp_len);
@@ -3760,6 +3702,7 @@ SILC_SERVER_CMD_FUNC(kick)
 
   /* Check whether sender is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL,
                                         0, 2, tmp, tmp_len);
@@ -3769,6 +3712,7 @@ SILC_SERVER_CMD_FUNC(kick)
   /* Check that the kicker is channel operator or channel founder */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV,
                                         0, 2, tmp, tmp_len);
@@ -3776,30 +3720,25 @@ SILC_SERVER_CMD_FUNC(kick)
   }
 
   /* Get target Client ID */
-  target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
-  if (!target_idp) {
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id2, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CLIENT_ID, 0);
     goto out;
   }
-  client_id = silc_id_payload_parse_id(target_idp, target_idp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
-                                        SILC_STATUS_ERR_BAD_CLIENT_ID,
-                                        0, 2, target_idp, target_idp_len);
-    goto out;
-  }
 
   /* Get target client's entry */
   target_client = silc_idlist_find_client_by_id(server->local_list,
-                                               client_id, TRUE, NULL);
-  if (!target_client) {
+                                               SILC_ID_GET_ID(id2),
+                                               TRUE, NULL);
+  if (!target_client)
     target_client = silc_idlist_find_client_by_id(server->global_list,
-                                                 client_id, TRUE, NULL);
-  }
+                                                 SILC_ID_GET_ID(id2),
+                                                 TRUE, NULL);
 
   /* Check whether target client is on the channel */
   if (!silc_server_client_on_channel(target_client, channel, &chl)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+    target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
     silc_server_command_send_status_data2(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_USER_NOT_ON_CHANNEL,
                                          0, 2, target_idp, target_idp_len,
@@ -3810,6 +3749,7 @@ SILC_SERVER_CMD_FUNC(kick)
   /* Check that the target client is not channel founder. Channel founder
      cannot be kicked from the channel. */
   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
                                         0, 2, tmp, tmp_len);
@@ -3821,8 +3761,9 @@ SILC_SERVER_CMD_FUNC(kick)
   if (clen > 128)
     comment = NULL;
 
-
   /* Send the reply back to the client */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_KICK,
                                 SILC_STATUS_OK, 0, ident, 2,
                                 2, tmp, tmp_len,
@@ -3834,7 +3775,7 @@ SILC_SERVER_CMD_FUNC(kick)
                                     SILC_NOTIFY_TYPE_KICKED, 3,
                                     target_idp, target_idp_len,
                                     comment, comment ? strlen(comment) : 0,
-                                    idp->data, idp->len);
+                                    idp->data, silc_buffer_len(idp));
   silc_buffer_free(idp);
 
   /* Send KICKED notify to primary route */
@@ -3847,7 +3788,7 @@ SILC_SERVER_CMD_FUNC(kick)
     SilcBuffer ab =
       silc_argument_payload_encode_one(NULL, target_idp, target_idp_len, 3);
     SilcArgumentPayload args =
-      silc_argument_payload_parse(ab->data, ab->len, 1);
+      silc_argument_payload_parse(ab->data, silc_buffer_len(ab), 1);
 
     silc_server_inviteban_process(server, channel->invite_list, 1, args);
     silc_buffer_free(ab);
@@ -3884,19 +3825,22 @@ SILC_SERVER_CMD_FUNC(oper)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   unsigned char *username = NULL, *auth;
   SilcUInt32 tmp_len;
   SilcServerConfigAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
-  bool result = FALSE;
+  SilcBool result = FALSE;
   SilcPublicKey cached_key;
+  const char *hostname, *ip;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
 
+  silc_socket_stream_get_info(cmd->sock, NULL, &hostname, &ip, NULL);
+
   /* Get the username */
   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!username) {
@@ -3917,10 +3861,10 @@ SILC_SERVER_CMD_FUNC(oper)
   }
 
   /* Get the admin configuration */
-  admin = silc_server_config_find_admin(server, cmd->sock->ip,
+  admin = silc_server_config_find_admin(server, (char *)ip,
                                        username, client->nickname);
   if (!admin) {
-    admin = silc_server_config_find_admin(server, cmd->sock->hostname,
+    admin = silc_server_config_find_admin(server, (char *)hostname,
                                          username, client->nickname);
     if (!admin) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
@@ -3928,7 +3872,7 @@ SILC_SERVER_CMD_FUNC(oper)
                                            0);
       SILC_LOG_INFO(("OPER authentication failed for username '%s' by "
                     "nickname '%s' from %s", username,
-                    client->nickname, cmd->sock->hostname));
+                    client->nickname, hostname));
       goto out;
     }
   }
@@ -3949,7 +3893,9 @@ SILC_SERVER_CMD_FUNC(oper)
                                   admin->passphrase, admin->passphrase_len,
                                   idata->hash, client->id, SILC_ID_CLIENT);
   if (!result && admin->publickeys) {
-    cached_key = silc_server_get_public_key(server, admin->publickeys);
+    cached_key =
+      silc_server_get_public_key(server,
+                                SILC_SKR_USAGE_SERVICE_AUTHORIZATION, admin);
     if (!cached_key)
       goto out;
     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
@@ -3998,21 +3944,16 @@ SILC_TASK_CALLBACK(silc_server_command_detach_cb)
   QuitInternal q = (QuitInternal)context;
   SilcClientID *client_id = (SilcClientID *)q->sock;
   SilcClientEntry client;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
 
   client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (client && client->connection) {
     sock = client->connection;
 
-    /* If there is pending outgoing data for the client then purge it
-       to the network before closing connection. */
-    silc_server_packet_queue_purge(server, sock);
-
     /* Close the connection on our side */
     client->router = NULL;
     client->connection = NULL;
-    sock->user_data = NULL;
     silc_server_close_connection(server, sock);
   }
 
@@ -4046,7 +3987,7 @@ SILC_SERVER_CMD_FUNC(detach)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   QuitInternal q;
 
   if (server->config->detach_disabled) {
@@ -4056,7 +3997,7 @@ SILC_SERVER_CMD_FUNC(detach)
     goto out;
   }
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_DETACH, cmd, 0, 0);
@@ -4084,16 +4025,16 @@ SILC_SERVER_CMD_FUNC(detach)
 
   q = silc_calloc(1, sizeof(*q));
   q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
-  silc_schedule_task_add(server->schedule, 0, silc_server_command_detach_cb,
-                        q, 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_command_detach_cb,
+                                q, 0, 200000);
 
   if (server->config->detach_timeout) {
     q = silc_calloc(1, sizeof(*q));
     q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_command_detach_timeout,
-                          q, server->config->detach_timeout * 60,
-                          0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_command_detach_timeout,
+                                  q, server->config->detach_timeout * 60, 0);
   }
 
   /* Send reply to the sender */
@@ -4114,7 +4055,7 @@ SILC_SERVER_CMD_FUNC(watch)
   SilcUInt32 add_nick_len, del_nick_len, tmp_len, pk_len;
   unsigned char hash[SILC_HASH_MAXLEN], *tmp,  *pk, *nick;
   SilcClientEntry client;
-  SilcClientID *client_id = NULL;
+  SilcID id;
   SilcUInt16 old_ident;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
@@ -4140,7 +4081,7 @@ SILC_SERVER_CMD_FUNC(watch)
 
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_WATCH,
@@ -4176,30 +4117,23 @@ SILC_SERVER_CMD_FUNC(watch)
  process_watch:
 
   /* Get the client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                          0);
     goto out;
   }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!client_id) {
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
-                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                        0, 2, tmp, tmp_len);
-    goto out;
-  }
 
   /* Get the client entry which must be in local list */
   client = silc_idlist_find_client_by_id(server->local_list,
-                                        client_id, TRUE, NULL);
+                                        SILC_ID_GET_ID(id), TRUE, NULL);
   if (!client) {
     /* Backup checks global list also */
     if (server->server_type == SILC_BACKUP_ROUTER)
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, TRUE, NULL);
+                                            SILC_ID_GET_ID(id), TRUE, NULL);
     if (!client) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
                                           0, 2, tmp, tmp_len);
@@ -4325,7 +4259,7 @@ SILC_SERVER_CMD_FUNC(watch)
 
     pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
     while (pk) {
-      if (!silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key))
+      if (!silc_public_key_payload_decode(pk, pk_len, &public_key))
        continue;
       if (type == 0x03)
         type = 0x00;
@@ -4399,15 +4333,16 @@ SILC_SERVER_CMD_FUNC(watch)
     old_ident = silc_command_get_ident(cmd->payload);
     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-    silc_server_backup_send(server, cmd->sock->user_data, SILC_PACKET_COMMAND,
-                           cmd->packet->flags, tmpbuf->data, tmpbuf->len,
+    silc_server_backup_send(server, silc_packet_get_context(cmd->sock),
+                           SILC_PACKET_COMMAND,
+                           cmd->packet->flags, tmpbuf->data,
+                           silc_buffer_len(tmpbuf),
                            FALSE, TRUE);
     silc_command_set_ident(cmd->payload, old_ident);
     silc_buffer_free(tmpbuf);
   }
 
  out:
-  silc_free(client_id);
   silc_server_command_free(cmd);
 }
 
@@ -4418,19 +4353,22 @@ SILC_SERVER_CMD_FUNC(silcoper)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   unsigned char *username = NULL, *auth;
   SilcUInt32 tmp_len;
   SilcServerConfigAdmin *admin;
   SilcIDListData idata = (SilcIDListData)client;
-  bool result = FALSE;
+  SilcBool result = FALSE;
   SilcPublicKey cached_key;
+  const char *hostname, *ip;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
 
+  silc_socket_stream_get_info(cmd->sock, NULL, &hostname, &ip, NULL);
+
   if (server->server_type != SILC_ROUTER) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                          SILC_STATUS_ERR_AUTH_FAILED, 0);
@@ -4457,17 +4395,17 @@ SILC_SERVER_CMD_FUNC(silcoper)
   }
 
   /* Get the admin configuration */
-  admin = silc_server_config_find_admin(server, cmd->sock->ip,
+  admin = silc_server_config_find_admin(server, (char *)ip,
                                        username, client->nickname);
   if (!admin) {
-    admin = silc_server_config_find_admin(server, cmd->sock->hostname,
+    admin = silc_server_config_find_admin(server, (char *)hostname,
                                          username, client->nickname);
     if (!admin) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                            SILC_STATUS_ERR_AUTH_FAILED, 0);
       SILC_LOG_INFO(("SILCOPER authentication failed for username '%s' by "
                     "nickname '%s' from %s", username,
-                    client->nickname, cmd->sock->hostname));
+                    client->nickname, hostname));
       goto out;
     }
   }
@@ -4488,7 +4426,9 @@ SILC_SERVER_CMD_FUNC(silcoper)
                                   admin->passphrase, admin->passphrase_len,
                                   idata->hash, client->id, SILC_ID_CLIENT);
   if (!result && admin->publickeys) {
-    cached_key = silc_server_get_public_key(server, admin->publickeys);
+    cached_key =
+      silc_server_get_public_key(server,
+                                SILC_SKR_USAGE_SERVICE_AUTHORIZATION, admin);
     if (!cached_key)
       goto out;
     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
@@ -4537,12 +4477,12 @@ SILC_SERVER_CMD_FUNC(ban)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcBuffer list, tmp2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
-  SilcChannelID *channel_id = NULL;
-  unsigned char *id, *tmp, *atype = NULL;
+  SilcID id;
+  unsigned char *tmp_id, *tmp, *atype = NULL;
   SilcUInt32 id_len, len, len2;
   SilcArgumentPayload args;
   SilcHashTableList htl;
@@ -4550,50 +4490,50 @@ SILC_SERVER_CMD_FUNC(ban)
   SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
   SilcBufferStruct blist;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
 
   /* Get Channel ID */
-  id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
-  if (id) {
-    channel_id = silc_id_payload_parse_id(id, id_len, NULL);
-    if (!channel_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-      goto out;
-    }
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
+    goto out;
   }
 
   /* Get channel entry. The server must know about the channel since the
      client is expected to be on the channel. */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
-      silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
+      tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
+      silc_server_command_send_status_data(
+                                          cmd, SILC_COMMAND_BAN,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
-                                          0, 2, id, id_len);
+                                          0, 2, tmp_id, id_len);
       goto out;
     }
   }
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
-                                        2, id, id_len);
+                                        2, tmp_id, id_len);
     goto out;
   }
 
   /* The client must be at least channel operator. */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+    tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0,
-                                        2, id, id_len);
+                                        2, tmp_id, id_len);
     goto out;
   }
 
@@ -4654,7 +4594,7 @@ SILC_SERVER_CMD_FUNC(ban)
                       SILC_STR_END);
     silc_hash_table_list(channel->ban_list, &htl);
     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
-      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+      list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
                                              type);
     silc_hash_table_list_reset(&htl);
   }
@@ -4671,7 +4611,7 @@ SILC_SERVER_CMD_FUNC(ban)
                                         id, id_len,
                                         atype, 1,
                                         tmp ? blist.data : NULL,
-                                        tmp ? blist.len : 0);
+                                        tmp ? silc_buffer_len(&blist) : 0);
 
     /* Send to network. */
     silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server),
@@ -4684,11 +4624,10 @@ SILC_SERVER_CMD_FUNC(ban)
                                 SILC_STATUS_OK, 0, ident, 2,
                                 2, id, id_len,
                                 3, list ? list->data : NULL,
-                                list ? list->len : 0);
+                                list ? silc_buffer_len(list) : 0);
   silc_buffer_free(list);
 
  out:
-  silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
@@ -4698,37 +4637,33 @@ SILC_SERVER_CMD_FUNC(leave)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcSocketConnection sock = cmd->sock;
-  SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
-  SilcChannelID *id = NULL;
+  SilcPacketStream sock = cmd->sock;
+  SilcClientEntry id_entry = silc_packet_get_context(cmd->sock);
+  SilcID id;
   SilcChannelEntry channel;
   SilcUInt32 len;
   unsigned char *tmp;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !id_entry)
+  if (id_entry->data.conn_type != SILC_CONN_CLIENT || !id_entry)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-  if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-  id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!id) {
+  if (!silc_argument_get_decoded(cmd->args, 1, SILC_ARGUMENT_ID, &id, NULL)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
     goto out;
   }
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+  channel = silc_idlist_find_channel_by_id(server->local_list,
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+    channel = silc_idlist_find_channel_by_id(server->global_list,
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
                                           0, 2, tmp, len);
@@ -4738,6 +4673,7 @@ SILC_SERVER_CMD_FUNC(leave)
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(id_entry, channel, NULL)) {
+    tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
     silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
                                         2, tmp, len);
@@ -4749,6 +4685,7 @@ SILC_SERVER_CMD_FUNC(leave)
   silc_server_send_notify_leave(server, SILC_PRIMARY_ROUTE(server),
                                SILC_BROADCAST(server), channel, id_entry->id);
 
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
   silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
                                       SILC_STATUS_OK, 0, 2, tmp, len);
 
@@ -4770,7 +4707,6 @@ SILC_SERVER_CMD_FUNC(leave)
   }
 
  out:
-  silc_free(id);
   silc_server_command_free(cmd);
 }
 
@@ -4782,8 +4718,9 @@ SILC_SERVER_CMD_FUNC(users)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   SilcChannelEntry channel;
-  SilcChannelID *id = NULL;
+  SilcID id;
   SilcBuffer idp;
   unsigned char *channel_id;
   SilcUInt32 channel_id_len;
@@ -4821,8 +4758,7 @@ SILC_SERVER_CMD_FUNC(users)
 
   /* Check Channel ID */
   if (channel_id) {
-    id = silc_id_payload_parse_id(channel_id, channel_id_len, NULL);
-    if (!id) {
+    if (!silc_id_payload_parse_id(channel_id, channel_id_len, &id)) {
       silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
                                           SILC_STATUS_ERR_BAD_CHANNEL_ID, 0,
                                           2, channel_id, channel_id_len);
@@ -4833,8 +4769,9 @@ SILC_SERVER_CMD_FUNC(users)
   /* If we are server and we don't know about this channel we will send
      the command to our router. If we know about the channel then we also
      have the list of users already. */
-  if (id)
-    channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+  if (channel_id)
+    channel = silc_idlist_find_channel_by_id(server->local_list,
+                                            SILC_ID_GET_ID(id), NULL);
   else
     channel = silc_idlist_find_channel_by_name(server->local_list,
                                               channel_namec, NULL);
@@ -4854,7 +4791,7 @@ SILC_SERVER_CMD_FUNC(users)
       /* Send USERS command */
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply */
       silc_server_command_pending(server, SILC_COMMAND_USERS,
@@ -4864,19 +4801,19 @@ SILC_SERVER_CMD_FUNC(users)
       cmd->pending = TRUE;
       silc_command_set_ident(cmd->payload, ident);
       silc_buffer_free(tmpbuf);
-      silc_free(id);
       goto out;
     }
 
     /* Check the global list as well. */
-    if (id)
-      channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+    if (channel_id)
+      channel = silc_idlist_find_channel_by_id(server->global_list,
+                                              SILC_ID_GET_ID(id), NULL);
     else
       channel = silc_idlist_find_channel_by_name(server->global_list,
                                                 channel_namec, NULL);
     if (!channel) {
       /* Channel really does not exist */
-      if (id)
+      if (channel_id)
        silc_server_command_send_status_data(
                                    cmd, SILC_COMMAND_USERS,
                                    SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID, 0,
@@ -4892,9 +4829,9 @@ SILC_SERVER_CMD_FUNC(users)
 
   /* If the channel is private or secret do not send anything, unless the
      user requesting this command is on the channel or is server */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+  if (idata->conn_type == SILC_CONN_CLIENT) {
     if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)
-       && !silc_server_client_on_channel(cmd->sock->user_data, channel,
+       && !silc_server_client_on_channel((SilcClientEntry)idata, channel,
                                          NULL)) {
       silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
@@ -4919,22 +4856,21 @@ SILC_SERVER_CMD_FUNC(users)
   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_USERS,
                                 SILC_STATUS_OK, 0, ident, 4,
-                                2, idp->data, idp->len,
+                                2, idp->data, silc_buffer_len(idp),
                                 3, lc, 4,
                                 4, client_id_list ?
                                 client_id_list->data : NULL,
                                 client_id_list ?
-                                client_id_list->len : 0,
+                                silc_buffer_len(client_id_list) : 0,
                                 5, client_mode_list ?
                                 client_mode_list->data : NULL,
                                 client_mode_list ?
-                                client_mode_list->len : 0);
+                                silc_buffer_len(client_mode_list) : 0);
   silc_buffer_free(idp);
   if (client_id_list)
     silc_buffer_free(client_id_list);
   if (client_mode_list)
     silc_buffer_free(client_mode_list);
-  silc_free(id);
 
  out:
   silc_free(channel_namec);
@@ -4950,8 +4886,8 @@ SILC_SERVER_CMD_FUNC(getkey)
   SilcServer server = cmd->server;
   SilcClientEntry client;
   SilcServerEntry server_entry;
-  SilcClientID *client_id = NULL;
-  SilcServerID *server_id = NULL;
+  SilcClientID client_id;
+  SilcServerID server_id;
   SilcIDPayload idp = NULL;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   unsigned char *tmp;
@@ -4977,15 +4913,15 @@ SILC_SERVER_CMD_FUNC(getkey)
 
   id_type = silc_id_payload_get_type(idp);
   if (id_type == SILC_ID_CLIENT) {
-    client_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &client_id, sizeof(client_id));
 
     /* If the client is not found from local list there is no chance it
        would be locally connected client so send the command further. */
     client = silc_idlist_find_client_by_id(server->local_list,
-                                          client_id, TRUE, NULL);
+                                          &client_id, TRUE, NULL);
     if (!client)
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, TRUE, NULL);
+                                            &client_id, TRUE, NULL);
 
     if ((!client && !cmd->pending && !server->standalone) ||
        (client && !client->connection && !cmd->pending &&
@@ -4993,10 +4929,10 @@ SILC_SERVER_CMD_FUNC(getkey)
        (client && !client->data.public_key && !cmd->pending)) {
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
-      SilcSocketConnection dest_sock;
+      SilcPacketStream dest_sock;
 
       dest_sock = silc_server_get_client_route(server, NULL, 0,
-                                              client_id, NULL, NULL);
+                                              &client_id, NULL, NULL);
       if (!dest_sock)
        goto out;
 
@@ -5009,7 +4945,7 @@ SILC_SERVER_CMD_FUNC(getkey)
 
       silc_server_packet_send(server, dest_sock,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
@@ -5034,17 +4970,17 @@ SILC_SERVER_CMD_FUNC(getkey)
        send just OK reply */
     public_key = client->data.public_key;
     if (public_key)
-      pk = silc_pkcs_public_key_payload_encode(public_key);
+      pk = silc_public_key_payload_encode(public_key);
   } else if (id_type == SILC_ID_SERVER) {
-    server_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &server_id, sizeof(server_id));
 
     /* If the server is not found from local list there is no chance it
        would be locally connected server so send the command further. */
     server_entry = silc_idlist_find_server_by_id(server->local_list,
-                                                server_id, TRUE, NULL);
+                                                &server_id, TRUE, NULL);
     if (!server_entry)
       server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                  server_id, TRUE, NULL);
+                                                  &server_id, TRUE, NULL);
 
     if (server_entry != server->id_entry &&
        ((!server_entry && !cmd->pending && !server->standalone) ||
@@ -5064,7 +5000,7 @@ SILC_SERVER_CMD_FUNC(getkey)
 
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
-                             tmpbuf->data, tmpbuf->len, TRUE);
+                             tmpbuf->data, silc_buffer_len(tmpbuf));
 
       /* Reprocess this packet after received reply from router */
       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
@@ -5089,7 +5025,7 @@ SILC_SERVER_CMD_FUNC(getkey)
                  (server_entry == server->id_entry ? server->public_key :
                   NULL) : server_entry->data.public_key);
     if (public_key)
-      pk = silc_pkcs_public_key_payload_encode(public_key);
+      pk = silc_public_key_payload_encode(public_key);
   } else {
     goto out;
   }
@@ -5099,14 +5035,12 @@ SILC_SERVER_CMD_FUNC(getkey)
                                 SILC_STATUS_OK, 0, ident, 2,
                                 2, tmp, tmp_len,
                                 3, pk ? pk->data : NULL,
-                                pk ? pk->len : 0);
+                                pk ? silc_buffer_len(pk) : 0);
 
  out:
   if (idp)
     silc_id_payload_free(idp);
   silc_buffer_free(pk);
-  silc_free(client_id);
-  silc_free(server_id);
   silc_server_command_free(cmd);
 }
 
@@ -5119,7 +5053,7 @@ SILC_SERVER_CMD_FUNC(service)
   SilcServer server = cmd->server;
   SilcUInt32 tmp_len, auth_len;
   unsigned char *service_name, *auth;
-  bool send_list = FALSE;
+  SilcBool send_list = FALSE;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SERVICE, cmd, 0, 256);
@@ -5164,12 +5098,12 @@ SILC_SERVER_CMD_FUNC(connect)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   unsigned char *tmp, *host;
   SilcUInt32 tmp_len;
   SilcUInt32 port = SILC_PORT;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
@@ -5204,7 +5138,7 @@ SILC_SERVER_CMD_FUNC(connect)
     SILC_GET32_MSB(port, tmp);
 
   /* Create the connection. It is done with timeout and is async. */
-  silc_server_create_connection(server, host, port);
+  silc_server_create_connection(server, FALSE, host, port, NULL, NULL);
 
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
@@ -5220,15 +5154,15 @@ SILC_SERVER_CMD_FUNC(close)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
   SilcServerEntry server_entry;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   unsigned char *name;
   SilcUInt32 port = SILC_PORT;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
@@ -5278,7 +5212,7 @@ SILC_SERVER_CMD_FUNC(close)
                                        SILC_STATUS_OK, 0);
 
   /* Close the connection to the server */
-  sock = (SilcSocketConnection)server_entry->connection;
+  sock = server_entry->connection;
 
   if (server_entry->server_type == SILC_BACKUP_ROUTER) {
     server->backup_closed = TRUE;
@@ -5294,8 +5228,7 @@ SILC_SERVER_CMD_FUNC(close)
   silc_server_disconnect_remote(server, sock,
                                SILC_STATUS_ERR_BANNED_FROM_SERVER,
                                "Closed by administrator");
-  if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock, NULL);
+  silc_server_free_sock_user_data(server, sock, NULL);
   server->backup_noswitch = FALSE;
 
  out:
@@ -5309,9 +5242,9 @@ SILC_SERVER_CMD_FUNC(shutdown)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+  if (client->data.conn_type != SILC_CONN_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);
index ba7fd2ce2d9383105a580b9de52890fac712f866..b9b7e2fef61d6c38cc6834cda95eb4d426020eea 100644 (file)
@@ -1,10 +1,11 @@
+
 /*
 
   servercommand.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -49,10 +50,10 @@ extern SilcServerCommand silc_command_list[];
 /* Context sent as argument to all commands */
 typedef struct {
   SilcServer server;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   SilcCommandPayload payload;
   SilcArgumentPayload args;
-  SilcPacketContext *packet;
+  SilcPacket packet;
   int pending;                 /* Command is being re-processed when TRUE */
   int users;                   /* Reference counter */
 } *SilcServerCommandContext;
@@ -99,18 +100,18 @@ do {                                                                       \
 
 /* Prototypes */
 void silc_server_command_process(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet);
+                                SilcPacketStream sock,
+                                SilcPacket packet);
 SilcServerCommandContext silc_server_command_alloc();
 void silc_server_command_free(SilcServerCommandContext ctx);
 SilcServerCommandContext
 silc_server_command_dup(SilcServerCommandContext ctx);
-bool silc_server_command_pending(SilcServer server,
+SilcBool silc_server_command_pending(SilcServer server,
                                 SilcCommand reply_cmd,
                                 SilcUInt16 ident,
                                 SilcCommandCb callback,
                                 void *context);
-bool silc_server_command_pending_timed(SilcServer server,
+SilcBool silc_server_command_pending_timed(SilcServer server,
                                       SilcCommand reply_cmd,
                                       SilcUInt16 ident,
                                       SilcCommandCb callback,
index 78dd08cfd9a358188b1e27e1bdbbd63b43d6f280..d9ebf2933c8630c9f2e7dbf3c0943efeb4f20047 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -60,9 +60,10 @@ SilcServerCommandReply silc_command_reply_list[] =
 /* Process received command reply. */
 
 void silc_server_command_reply_process(SilcServer server,
-                                      SilcSocketConnection sock,
+                                      SilcPacketStream sock,
                                       SilcBuffer buffer)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcServerCommandReply *cmd;
   SilcServerCommandReplyContext ctx;
   SilcCommandPayload payload;
@@ -71,7 +72,7 @@ void silc_server_command_reply_process(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   /* Get command reply payload from packet */
-  payload = silc_command_payload_parse(buffer->data, buffer->len);
+  payload = silc_command_payload_parse(buffer->data, silc_buffer_len(buffer));
   if (!payload) {
     /* Silently ignore bad reply packet */
     SILC_LOG_DEBUG(("Bad command reply packet"));
@@ -82,14 +83,15 @@ void silc_server_command_reply_process(SilcServer server,
      command reply routine receiving it. */
   ctx = silc_calloc(1, sizeof(*ctx));
   ctx->server = server;
-  ctx->sock = silc_socket_dup(sock);
+  ctx->sock = sock;
   ctx->payload = payload;
   ctx->args = silc_command_get_args(ctx->payload);
   ctx->ident = silc_command_get_ident(ctx->payload);
   command = silc_command_get(ctx->payload);
+  silc_packet_stream_ref(sock);
 
   /* Client is not allowed to send reply to all commands */
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT &&
+  if (idata->conn_type == SILC_CONN_CLIENT &&
       command != SILC_COMMAND_WHOIS) {
     silc_server_command_reply_free(ctx);
     return;
@@ -120,7 +122,7 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
   if (cmd) {
     silc_command_payload_free(cmd->payload);
     if (cmd->sock)
-      silc_socket_free(cmd->sock); /* Decrease the reference counter */
+      silc_packet_stream_unref(cmd->sock);
     silc_free(cmd->callbacks);
     silc_free(cmd);
   }
@@ -131,35 +133,32 @@ silc_server_command_process_error(SilcServerCommandReplyContext cmd,
                                  SilcStatus error)
 {
   SilcServer server = cmd->server;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
 
   /* If we received notify for invalid ID we'll remove the ID if we
      have it cached. */
   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
-      cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      idata->conn_type == SILC_CONN_ROUTER) {
     SilcClientEntry client;
-    SilcUInt32 tmp_len;
-    unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-    if (tmp) {
-      SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-      if (client_id) {
-       SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
-                       "the entry from cache"));
-       client = silc_idlist_find_client_by_id(server->global_list,
-                                              client_id, FALSE, NULL);
-       if (client) {
-
-         if (client->data.public_key)
-           silc_hash_table_del_by_context(server->pk_hash,
-                                           client->data.public_key,
-                                           client);
-
-         silc_server_remove_from_channels(server, NULL, client, TRUE,
-                                          NULL, TRUE, FALSE);
-         silc_idlist_del_data(client);
-         silc_idlist_del_client(server->global_list, client);
-       }
-       silc_free(client_id);
-      }
+    SilcID id;
+    if (silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id,
+                                 NULL)) {
+      SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
+                     "the entry from cache"));
+      client = silc_idlist_find_client_by_id(server->global_list,
+                                            SILC_ID_GET_ID(id), FALSE, NULL);
+      if (!client)
+       return;
+
+      if (client->data.public_key)
+       silc_hash_table_del_by_context(server->pk_hash,
+                                      client->data.public_key,
+                                      client);
+
+      silc_server_remove_from_channels(server, NULL, client, TRUE,
+                                      NULL, TRUE, FALSE);
+      silc_idlist_del_data(client);
+      silc_idlist_del_client(server->global_list, client);
     }
   }
 }
@@ -171,14 +170,16 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 {
   SilcServer server = cmd->server;
   unsigned char *id_data, *umodes;
-  char *nickname, *username, *realname, *tmp, *servername = NULL;
+  char *nickname, *username, *realname, *tmp;
   unsigned char *fingerprint;
-  SilcClientID *client_id;
+  SilcID id;
   SilcClientEntry client;
-  SilcIDCacheEntry cache = NULL;
   char global = FALSE;
-  char *nick = NULL;
+  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
   SilcUInt32 mode = 0, len, len2, id_len, flen;
+  const char *hostname, *ip;
+
+  silc_socket_stream_get_info(cmd->sock, NULL, &hostname, &ip, NULL);
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -191,18 +192,19 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
   if (tmp)
     SILC_GET32_MSB(mode, tmp);
 
-  client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
-  if (!client_id)
+  if (!silc_id_payload_parse_id(id_data, id_len, &id))
     return FALSE;
 
   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
 
   /* Check if we have this client cached already. */
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
+  client = silc_idlist_find_client_by_id(server->local_list,
+                                        SILC_ID_GET_ID(id),
                                         FALSE, NULL);
   if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list, client_id,
+    client = silc_idlist_find_client_by_id(server->global_list,
+                                          SILC_ID_GET_ID(id),
                                           FALSE, NULL);
     global = TRUE;
   }
@@ -214,18 +216,21 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be
        global. This will check for valid nickname and username strings. */
-    client = silc_idlist_add_client(server->global_list, nick, username,
-                                   strdup(realname), client_id,
-                                   cmd->sock->user_data, NULL, 0);
+    client = silc_idlist_add_client(server->global_list,
+                                   strdup(nick), username,
+                                   strdup(realname),
+                                   silc_id_dup(SILC_ID_GET_ID(id),
+                                               SILC_ID_CLIENT),
+                                   silc_packet_get_context(cmd->sock),
+                                   NULL);
     if (!client) {
       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-      silc_free(nick);
-      silc_free(servername);
       return FALSE;
     }
 
@@ -233,51 +238,46 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
       (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->mode = mode;
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
   } else {
     /* We have the client already, update the data */
 
     SILC_LOG_DEBUG(("Updating client data"));
 
     /* Check nickname */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
     if (!nickname) {
       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply "
                      "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", nick));
-      silc_free(nick);
-      silc_free(servername);
+                     hostname ? hostname : "", nick));
       return FALSE;
     }
 
     /* Check username */
-    silc_parse_userfqdn(username, &tmp, NULL);
-    if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) {
-      silc_free(tmp);
-      silc_free(nick);
-      silc_free(servername);
+    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
+    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) {
       SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply "
                      "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", tmp));
+                     hostname ? hostname : "", tmp));
       return FALSE;
     }
-    silc_free(tmp);
 
     /* Remove the old cache entry  */
     silc_idcache_del_by_context(global ? server->global_list->clients :
-                               server->local_list->clients, client);
+                               server->local_list->clients, client, NULL);
 
     silc_free(client->nickname);
     silc_free(client->username);
     silc_free(client->userinfo);
     silc_free(client->servername);
 
-    client->nickname = nick;
+    client->nickname = strdup(nick);
     client->username = strdup(username);
     client->userinfo = strdup(realname);
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
     client->mode = mode;
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
@@ -285,8 +285,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     /* Create new cache entry */
     silc_idcache_add(global ? server->global_list->clients :
                     server->local_list->clients, nickname, client->id,
-                    client, 0, NULL);
-    silc_free(client_id);
+                    client);
   }
 
   /* Save channel list if it was sent to us */
@@ -302,17 +301,6 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     } else {
       silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
     }
-
-    /* If client is global and is not on any channel then add that we'll
-       expire the entry after a while. */
-    if (global) {
-      silc_idlist_find_client_by_id(server->global_list, client->id,
-                                   FALSE, &cache);
-      if (!silc_hash_table_count(client->channels))
-       cache->expire = time(NULL) + 300;
-      else
-       cache->expire = 0;
-    }
   }
 
   if (fingerprint && flen == sizeof(client->data.fingerprint))
@@ -361,8 +349,9 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
            }
 
            /* Save the public key. */
-           if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
-                                            &client->data.public_key)) {
+           if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC,
+                                           pk.data, pk.data_len,
+                                           &client->data.public_key)) {
              silc_free(pk.type);
              silc_free(pk.data);
              continue;
@@ -398,7 +387,7 @@ silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
 {
   unsigned char *tmp;
   SilcUInt32 len;
-  SilcClientEntry client = cmd->sock->user_data;
+  SilcClientEntry client = silc_packet_get_context(cmd->sock);
 
   /* Take Requested Attributes if set. */
   tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
@@ -422,11 +411,12 @@ silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
 SILC_SERVER_CMD_REPLY_FUNC(whois)
 {
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   SilcStatus status, error;
 
   COMMAND_CHECK_STATUS;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
+  if (idata->conn_type != SILC_CONN_CLIENT) {
     if (!silc_server_command_reply_whois_save(cmd))
       goto out;
   } else {
@@ -460,12 +450,15 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
   SilcServer server = cmd->server;
   SilcUInt32 len, id_len;
   unsigned char *id_data;
-  char *nickname, *username, *realname, *servername = NULL, *tmp;
-  SilcClientID *client_id;
+  char *nickname, *username, *realname;
+  SilcID id;
   SilcClientEntry client;
   SilcIDCacheEntry cache = NULL;
-  char *nick = NULL;
+  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
   int global = FALSE;
+  const char *hostname, *ip;
+
+  silc_socket_stream_get_info(cmd->sock, NULL, &hostname, &ip, NULL);
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -475,17 +468,18 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
 
   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
 
-  client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
-  if (!client_id)
+  if (!silc_id_payload_parse_id(id_data, id_len, &id))
     return FALSE;
 
   /* Check if we have this client cached already. */
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
+  client = silc_idlist_find_client_by_id(server->local_list,
+                                        SILC_ID_GET_ID(id),
                                         FALSE, &cache);
   if (!client) {
     client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, FALSE, &cache);
+                                          SILC_ID_GET_ID(id),
+                                          FALSE, &cache);
     global = TRUE;
   }
 
@@ -496,87 +490,65 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
       return FALSE;
 
     /* Take hostname out of nick string if it includes it. */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
 
     /* We don't have that client anywhere, add it. The client is added
        to global list since server didn't have it in the lists so it must be
        global. */
-    client = silc_idlist_add_client(server->global_list, nick, username,
+    client = silc_idlist_add_client(server->global_list,
+                                   strdup(nick), username,
                                    strdup(realname),
-                                   silc_id_dup(client_id, SILC_ID_CLIENT),
-                                   cmd->sock->user_data, NULL,
-                                   SILC_ID_CACHE_EXPIRE_DEF);
+                                   silc_id_dup(SILC_ID_GET_ID(id),
+                                               SILC_ID_CLIENT),
+                                   silc_packet_get_context(cmd->sock), NULL);
     if (!client) {
       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-      silc_free(nick);
-      silc_free(servername);
       return FALSE;
     }
 
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
   } else {
     /* We have the client already, update the data */
 
     /* Check nickname */
-    silc_parse_userfqdn(nickname, &nick, &servername);
+    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
+                       sizeof(servername));
     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
     if (!nickname) {
       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply "
                      "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", nick));
-      silc_free(nick);
-      silc_free(servername);
+                     hostname ? hostname : "", nick));
       return FALSE;
     }
 
     /* Check username */
-    silc_parse_userfqdn(username, &tmp, NULL);
-    if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) {
-      silc_free(tmp);
-      silc_free(nick);
-      silc_free(servername);
-      SILC_LOG_ERROR(("Malformed username '%s' received in WHOWAS reply "
-                     "from %s",
-                     cmd->sock->hostname ? cmd->sock->hostname : "", tmp));
+    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
+    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128))
       return FALSE;
-    }
-    silc_free(tmp);
 
     silc_free(client->nickname);
     silc_free(client->username);
     silc_free(client->servername);
 
-    client->nickname = nick;
+    client->nickname = strdup(nick);
     client->username = strdup(username);
-    client->servername = servername;
+    client->servername = servername[0] ? strdup(servername) : NULL;
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
 
     /* Remove the old cache entry and create a new one */
     silc_idcache_del_by_context(global ? server->global_list->clients :
-                               server->local_list->clients, client);
+                               server->local_list->clients, client, NULL);
     silc_idcache_add(global ? server->global_list->clients :
                     server->local_list->clients, nickname, client->id,
-                    client, 0, NULL);
+                    client);
   }
 
-  /* If client is global and is not on any channel then add that we'll
-     expire the entry after a while. */
-  if (global) {
-    silc_idlist_find_client_by_id(server->global_list, client->id,
-                                 FALSE, &cache);
-    if (!silc_hash_table_count(client->channels))
-      cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-    else
-      cache->expire = 0;
-  }
-
-  silc_free(client_id);
-
   return TRUE;
 }
 
@@ -620,17 +592,16 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
   SilcUInt32 len, id_len;
   unsigned char *id_data;
   char *name, *info;
-  SilcClientID *client_id = NULL;
-  SilcServerID *server_id = NULL;
-  SilcChannelID *channel_id = NULL;
+  SilcClientID client_id;
+  SilcServerID server_id;
+  SilcChannelID*channel_id;
   SilcClientEntry client;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
   char global = FALSE;
-  char *nick = NULL;
+  char nick[128 + 1];
   SilcIDPayload idp = NULL;
   SilcIdType id_type;
-  int expire = 0;
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   if (!id_data)
@@ -646,16 +617,15 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
   switch (id_type) {
   case SILC_ID_CLIENT:
-    client_id = silc_id_payload_get_id(idp);
-    if (!client_id)
+    if (!silc_id_payload_get_id(idp, &client_id, sizeof(client_id)))
       goto error;
 
     SILC_LOG_DEBUG(("Received client information"));
 
     client = silc_idlist_find_client_by_id(server->local_list,
-                                          client_id, FALSE, NULL);
+                                          &client_id, FALSE, NULL);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->global_list, client_id,
+      client = silc_idlist_find_client_by_id(server->global_list, &client_id,
                                             FALSE, NULL);
       global = TRUE;
     }
@@ -667,17 +637,18 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       /* Take nickname */
       if (name)
-       silc_parse_userfqdn(name, &nick, NULL);
+       silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0);
 
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be
         global. */
-      client = silc_idlist_add_client(server->global_list, nick, info, NULL,
-                                     client_id, cmd->sock->user_data,
-                                     NULL, time(NULL) + 300);
+      client = silc_idlist_add_client(server->global_list,
+                                     nick[0] ? nick : NULL, info, NULL,
+                                     silc_id_dup(&client_id, SILC_ID_CLIENT),
+                                     silc_packet_get_context(cmd->sock),
+                                     NULL);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-       silc_free(nick);
        goto error;
       }
 
@@ -691,30 +662,28 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       /* Take nickname */
       if (name) {
-       silc_parse_userfqdn(name, &nick, NULL);
+       silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0);
 
        /* Check nickname */
        name = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
                                     128, NULL);
        if (!name) {
-         SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY reply "
-                         "from %s",
-                         cmd->sock->hostname ?
-                         cmd->sock->hostname : "", nick));
+         SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY "
+                         "reply ", nick));
          return FALSE;
        }
 
        /* Remove the old cache entry */
        silc_idcache_del_by_context(global ? server->global_list->clients :
-                                   server->local_list->clients, client);
+                                   server->local_list->clients, client, NULL);
 
        silc_free(client->nickname);
-       client->nickname = nick;
+       client->nickname = strdup(nick);
 
        /* Add new cache entry */
        silc_idcache_add(global ? server->global_list->clients :
                         server->local_list->clients, name, client->id,
-                        client, expire, NULL);
+                        client);
       }
 
       if (info) {
@@ -724,20 +693,6 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
-
-      /* If client is global and is not on any channel then add that we'll
-         expire the entry after a while. */
-      if (global && server->server_type == SILC_SERVER) {
-       SilcIDCacheEntry cache = NULL;
-        silc_idlist_find_client_by_id(server->global_list, client->id,
-                                     FALSE, &cache);
-        if (!silc_hash_table_count(client->channels))
-         cache->expire = time(NULL) + 300;
-        else
-         cache->expire = 0;
-      }
-
-      silc_free(client_id);
     }
 
     break;
@@ -746,17 +701,16 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
     if (!name)
       goto error;
 
-    server_id = silc_id_payload_get_id(idp);
-    if (!server_id)
+    if (!silc_id_payload_get_id(idp, &server_id, sizeof(server_id)))
       goto error;
 
     SILC_LOG_DEBUG(("Received server information"));
 
     server_entry = silc_idlist_find_server_by_id(server->local_list,
-                                                server_id, FALSE, NULL);
+                                                &server_id, FALSE, NULL);
     if (!server_entry)
       server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                  server_id, FALSE, NULL);
+                                                  &server_id, FALSE, NULL);
     if (!server_entry) {
       /* If router did not find such Server ID in its lists then this must
         be bogus server or some router in the net is buggy. */
@@ -766,27 +720,25 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
       /* We don't have that server anywhere, add it. */
       server_entry = silc_idlist_add_server(server->global_list,
                                            strdup(name), 0,
-                                           server_id, server->router,
+                                           silc_id_dup(&server_id,
+                                                       SILC_ID_SERVER),
+                                           server->router,
                                            SILC_PRIMARY_ROUTE(server));
-      if (!server_entry) {
-       silc_free(server_id);
+      if (!server_entry)
        goto error;
-      }
+
       server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
       server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
-      server_id = NULL;
     }
 
-    silc_free(server_id);
     break;
 
   case SILC_ID_CHANNEL:
     if (!name)
       goto error;
 
-    channel_id = silc_id_payload_get_id(idp);
-    if (!channel_id)
+    if (!silc_id_payload_get_id(idp, &channel_id, sizeof(channel_id)))
       goto error;
 
     SILC_LOG_DEBUG(("Received channel information"));
@@ -812,18 +764,17 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       /* We don't have that channel anywhere, add it. */
       channel = silc_idlist_add_channel(server->global_list, strdup(name),
-                                       SILC_CHANNEL_MODE_NONE, channel_id,
+                                       SILC_CHANNEL_MODE_NONE,
+                                       silc_id_dup(&channel_id,
+                                                   SILC_ID_CHANNEL),
                                        server->router, NULL, NULL, 0);
       if (!channel) {
-       silc_free(channel_id);
        silc_free(info);
        goto error;
       }
       silc_free(info);
-      channel_id = NULL;
     }
 
-    silc_free(channel_id);
     break;
   }
 
@@ -876,18 +827,14 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcServerEntry entry;
-  SilcServerID *server_id;
+  SilcID id;
   SilcUInt32 tmp_len;
   unsigned char *tmp, *name;
 
   COMMAND_CHECK_STATUS;
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp)
-    goto out;
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   /* Get the name */
@@ -895,21 +842,23 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   if (!name)
     goto out;
 
-  entry = silc_idlist_find_server_by_id(server->local_list, server_id,
+  entry = silc_idlist_find_server_by_id(server->local_list,
+                                       SILC_ID_GET_ID(id),
                                        FALSE, NULL);
   if (!entry) {
-    entry = silc_idlist_find_server_by_id(server->global_list, server_id,
+    entry = silc_idlist_find_server_by_id(server->global_list,
+                                         SILC_ID_GET_ID(id),
                                          FALSE, NULL);
     if (!entry) {
       /* Add the server to global list */
-      server_id = silc_id_dup(server_id, SILC_ID_SERVER);
       entry = silc_idlist_add_server(server->global_list, strdup(name), 0,
-                                    server_id, cmd->sock->user_data,
+                                    silc_id_dup(SILC_ID_GET_ID(id),
+                                                SILC_ID_SERVER),
+                                    silc_packet_get_context(cmd->sock),
                                     cmd->sock);
-      if (!entry) {
-       silc_free(server_id);
+      if (!entry)
        goto out;
-      }
+
       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     }
   }
@@ -935,24 +884,22 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcServerEntry entry = NULL;
-  SilcServerID *server_id;
+  SilcID id;
   SilcUInt32 tmp_len;
   unsigned char *tmp;
 
   COMMAND_CHECK_STATUS;
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp)
-    goto out;
-  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!server_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
-  entry = silc_idlist_find_server_by_id(server->local_list, server_id,
+  entry = silc_idlist_find_server_by_id(server->local_list,
+                                       SILC_ID_GET_ID(id),
                                        TRUE, NULL);
   if (!entry) {
-    entry = silc_idlist_find_server_by_id(server->global_list, server_id,
+    entry = silc_idlist_find_server_by_id(server->global_list,
+                                         SILC_ID_GET_ID(id),
                                          TRUE, NULL);
     if (!entry) {
       SilcBuffer buffer;
@@ -968,6 +915,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
       /* entry isn't known so we IDENTIFY it. otherwise the
          silc_server_command_motd won't know about it and tell
          the client that there is no such server */
+      tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
       buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                              ++server->cmd_ident, 5,
                                              1, NULL, 0, 2, NULL, 0,
@@ -975,7 +923,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
                                              5, tmp, tmp_len);
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, 0, buffer->data,
-                             buffer->len, TRUE);
+                             silc_buffer_len(buffer));
       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
                                  server->cmd_ident,
                                  silc_server_command_reply_motd,
@@ -1011,12 +959,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   SilcServer server = cmd->server;
   SilcIDCacheEntry cache = NULL;
   SilcStatus status, error;
-  SilcChannelID *id;
-  SilcClientID *client_id = NULL;
+  SilcID id, id2;
   SilcChannelEntry entry;
   SilcHmac hmac = NULL;
-  SilcUInt32 id_len, len, list_count;
-  unsigned char *id_string;
+  SilcUInt32 len, list_count;
   char *channel_name, *channel_namec = NULL, *tmp;
   SilcUInt32 mode, created;
   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
@@ -1030,16 +976,11 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     goto out;
 
   /* Get channel ID */
-  id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
-  if (!id_string)
+  if (!silc_argument_get_decoded(cmd->args, 3, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   /* Get client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
-  if (!tmp)
-    goto out;
-  client_id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!client_id)
+  if (!silc_argument_get_decoded(cmd->args, 4, SILC_ARGUMENT_ID, &id2, NULL))
     goto out;
 
   /* Get mode mask */
@@ -1060,15 +1001,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
   if (tmp) {
     keyp = silc_buffer_alloc(len);
-    silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
+    silc_buffer_pull_tail(keyp, silc_buffer_truelen(keyp));
     silc_buffer_put(keyp, tmp, len);
   }
 
-  /* Parse the Channel ID */
-  id = silc_id_payload_parse_id(id_string, id_len, NULL);
-  if (!id)
-    goto out;
-
   /* Get hmac */
   tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
   if (tmp) {
@@ -1103,7 +1039,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   /* Get founder key */
   tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
   if (tmp)
-    silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
+    silc_public_key_payload_decode(tmp, len, &founder_key);
 
   /* See whether we already have the channel. */
   channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
@@ -1117,7 +1053,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
     SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
                    (created == 0 ? "existing" : "created"), channel_name,
-                   silc_id_render(id, SILC_ID_CHANNEL)));
+                   silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
 
     /* If the channel is found from global list we must move it to the
        local list. */
@@ -1128,12 +1064,13 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
     /* Add the channel to our local list. */
     entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
-                                   SILC_CHANNEL_MODE_NONE, id,
-                                   server->router, NULL, hmac, 0);
-    if (!entry) {
-      silc_free(id);
+                                   SILC_CHANNEL_MODE_NONE,
+                                   silc_id_dup(SILC_ID_GET_ID(id),
+                                               SILC_ID_CHANNEL),
+                                   server->router, NULL, NULL, hmac);
+    if (!entry)
       goto out;
-    }
+
     hmac = NULL;
     server->stat.my_channels++;
     server->stat.channels++;
@@ -1141,8 +1078,9 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     /* The entry exists. */
 
     /* If ID has changed, then update it to the cache too. */
-    if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
-      silc_idlist_replace_channel_id(server->local_list, entry->id, id);
+    if (!SILC_ID_CHANNEL_COMPARE(entry->id, SILC_ID_GET_ID(id)))
+      silc_idlist_replace_channel_id(server->local_list, entry->id,
+                                    SILC_ID_GET_ID(id));
 
     entry->disabled = FALSE;
 
@@ -1232,11 +1170,8 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   entry->global_users = (created == 0 ? TRUE : FALSE);
 
   /* If channel was just created the mask must be zero */
-  if (!entry->global_users && mode) {
-    SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
-                   "new channel, forcing it to zero", cmd->sock->hostname));
+  if (!entry->global_users && mode)
     mode = 0;
-  }
 
   /* Save channel mode */
   entry->mode = mode;
@@ -1250,7 +1185,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
   /* Save the users to the channel */
   silc_server_save_users_on_channel(server, cmd->sock, entry,
-                                   client_id, client_id_list,
+                                   SILC_ID_GET_ID(id2), client_id_list,
                                    client_mode_list, list_count);
   entry->users_resolved = TRUE;
 
@@ -1260,7 +1195,6 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   silc_free(channel_namec);
   if (hmac)
     silc_hmac_free(hmac);
-  silc_free(client_id);
   silc_server_command_reply_free(cmd);
 
   silc_pkcs_public_key_free(founder_key);
@@ -1318,7 +1252,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
   SilcServer server = cmd->server;
   SilcStatus status, error;
   SilcChannelEntry channel;
-  SilcChannelID *channel_id = NULL;
+  SilcID id;
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
   unsigned char *tmp;
@@ -1328,29 +1262,25 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
   COMMAND_CHECK_STATUS;
 
   /* Get channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp)
-    goto out;
-  channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-  if (!channel_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list,
-                                          channel_id, NULL);
+                                          SILC_ID_GET_ID(id), NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
       SilcBuffer idp;
 
       if (server->server_type != SILC_SERVER)
        goto out;
 
-      idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+      idp = silc_id_payload_encode(SILC_ID_GET_ID(id), SILC_ID_CHANNEL);
       silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
                               SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
-                              1, 5, idp->data, idp->len);
+                              1, 5, idp->data, silc_buffer_len(idp));
       silc_buffer_free(idp);
 
       /* Register pending command callback. After we've received the channel
@@ -1400,7 +1330,6 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
 
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
-  silc_free(channel_id);
  err:
   silc_server_command_reply_free(cmd);
 }
@@ -1412,8 +1341,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
   SilcStatus status, error;
   SilcClientEntry client = NULL;
   SilcServerEntry server_entry = NULL;
-  SilcClientID *client_id = NULL;
-  SilcServerID *server_id = NULL;
+  SilcClientID client_id;
+  SilcServerID server_id;
   unsigned char *tmp;
   SilcUInt32 len;
   SilcIDPayload idp = NULL;
@@ -1435,18 +1364,18 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
     goto out;
 
   /* Decode the public key payload */
-  if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+  if (!silc_public_key_payload_decode(tmp, len, &public_key))
     goto out;
 
   id_type = silc_id_payload_get_type(idp);
   if (id_type == SILC_ID_CLIENT) {
-    client_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &client_id, sizeof(client_id));
 
-    client = silc_idlist_find_client_by_id(server->local_list, client_id,
+    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, TRUE, NULL);
+                                            &client_id, TRUE, NULL);
       if (!client)
        goto out;
     }
@@ -1460,13 +1389,13 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
       public_key = NULL;
     }
   } else if (id_type == SILC_ID_SERVER) {
-    server_id = silc_id_payload_get_id(idp);
+    silc_id_payload_get_id(idp, &server_id, sizeof(server_id));
 
-    server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
-                                                TRUE, NULL);
+    server_entry = silc_idlist_find_server_by_id(server->local_list,
+                                                &server_id, TRUE, NULL);
     if (!server_entry) {
       server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                  server_id, TRUE, NULL);
+                                                  &server_id, TRUE, NULL);
       if (!server_entry)
        goto out;
     }
@@ -1481,8 +1410,6 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
   if (idp)
     silc_id_payload_free(idp);
-  silc_free(client_id);
-  silc_free(server_id);
   if (public_key)
     silc_pkcs_public_key_free(public_key);
  err:
@@ -1494,21 +1421,16 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
   SilcServer server = cmd->server;
   SilcStatus status, error;
-  SilcChannelID *channel_id = NULL;
+  SilcID id;
   SilcChannelEntry channel;
   SilcIDCacheEntry cache;
-  SilcUInt32 len;
   unsigned char *tmp, *name, *namec = NULL, *topic;
   SilcUInt32 usercount = 0;
-  bool global_list = FALSE;
+  SilcBool global_list = FALSE;
 
   COMMAND_CHECK_STATUS;
 
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
-  if (!tmp)
-    goto out;
-  channel_id = silc_id_payload_parse_id(tmp, len, NULL);
-  if (!channel_id)
+  if (!silc_argument_get_decoded(cmd->args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
 
   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
@@ -1537,16 +1459,12 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
       goto out;
 
     channel = silc_idlist_add_channel(server->global_list, strdup(name),
-                                     SILC_CHANNEL_MODE_NONE, channel_id,
-                                     server->router, NULL, NULL,
-                                     time(NULL) + 60);
+                                     SILC_CHANNEL_MODE_NONE,
+                                     silc_id_dup(SILC_ID_GET_ID(id),
+                                                 SILC_ID_CHANNEL),
+                                     server->router, NULL, NULL, NULL);
     if (!channel)
       goto out;
-    channel_id = NULL;
-  } else {
-    /* Found, update expiry */
-    if (global_list && server->server_type == SILC_SERVER)
-      cache->expire = time(NULL) + 60;
   }
 
   channel->user_count = usercount;
@@ -1563,13 +1481,8 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
     return;
   }
 
-  /* Now purge all old entries from the global list, otherwise we'll might
-     have non-existent entries for long periods of time in the cache. */
-  silc_idcache_purge(server->global_list->channels);
-
  out:
   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
-  silc_free(channel_id);
  err:
   silc_free(namec);
   silc_server_command_reply_free(cmd);
index 371cce46d4ecb572012d01c6612225aae98ef227..2b3671871c173146f07853c7abcebf191800b175 100644 (file)
@@ -41,7 +41,7 @@ typedef struct {
 /* Context sent as argument to all command reply functions */
 typedef struct {
   SilcServer server;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   SilcCommandPayload payload;
   SilcArgumentPayload args;
 
@@ -64,7 +64,7 @@ void silc_server_command_reply_##func(void *context, void *context2)
 /* Prototypes */
 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd);
 void silc_server_command_reply_process(SilcServer server,
-                                      SilcSocketConnection sock,
+                                      SilcPacketStream sock,
                                       SilcBuffer buffer);
 SILC_SERVER_CMD_REPLY_FUNC(whois);
 SILC_SERVER_CMD_REPLY_FUNC(whowas);
index a0e676e002fc41cfe01164b82103e6fb049b52f6..2cdf77fb174cb3c510cf39f49bb7dadb415f204a 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 
 void silc_idlist_add_data(void *entry, SilcIDListData idata)
 {
-  SilcIDListData data = (SilcIDListData)entry;
-  data->send_key = idata->send_key;
-  data->receive_key = idata->receive_key;
-  data->hmac_send = idata->hmac_send;
-  data->hmac_receive = idata->hmac_receive;
-  data->psn_send = idata->psn_send;
-  data->psn_receive = idata->psn_receive;
+  SilcIDListData data = entry;
   data->hash = idata->hash;
   data->public_key = idata->public_key;
   memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint));
@@ -48,7 +42,6 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata)
   data->last_receive = idata->last_receive;
   data->last_sent = idata->last_sent;
   data->status = idata->status;
-
   data->created = time(0);     /* Update creation time */
 }
 
@@ -57,48 +50,31 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata)
 void silc_idlist_del_data(void *entry)
 {
   SilcIDListData idata = (SilcIDListData)entry;
-  if (idata->send_key)
-    silc_cipher_free(idata->send_key);
-  if (idata->receive_key)
-    silc_cipher_free(idata->receive_key);
-  if (idata->rekey) {
-    if (idata->rekey->send_enc_key) {
-      memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
-      silc_free(idata->rekey->send_enc_key);
-    }
-    silc_free(idata->rekey);
-  }
-  if (idata->hmac_send)
-    silc_hmac_free(idata->hmac_send);
-  if (idata->hmac_receive)
-    silc_hmac_free(idata->hmac_receive);
+
   if (idata->hash)
     silc_hash_free(idata->hash);
   if (idata->public_key)
     silc_pkcs_public_key_free(idata->public_key);
 
-  idata->send_key = NULL;
-  idata->receive_key = NULL;
-  idata->rekey = NULL;
-  idata->hmac_send = NULL;
-  idata->hmac_receive = NULL;
   idata->hash = NULL;
   idata->public_key = NULL;
 }
 
 /* Purges ID cache */
 
-SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
+SILC_TASK_CALLBACK(silc_idlist_purge)
 {
   SilcServer server = app_context;
   SilcIDListPurge i = (SilcIDListPurge)context;
 
   SILC_LOG_DEBUG(("Purging cache"));
 
+#if 0
+  /* XXX */
   silc_idcache_purge(i->cache);
-  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
-                        (void *)i, i->timeout, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge, i,
+                                i->timeout, 0);
+#endif
 }
 
 /******************************************************************************
@@ -139,7 +115,7 @@ silc_idlist_add_server(SilcIDList id_list,
   server->connection = connection;
 
   if (!silc_idcache_add(id_list->servers, server_namec,
-                       (void *)server->id, (void *)server, 0, NULL)) {
+                       (void *)server->id, (void *)server)) {
     silc_free(server);
     silc_free(server_namec);
     return NULL;
@@ -152,7 +128,7 @@ silc_idlist_add_server(SilcIDList id_list,
 
 SilcServerEntry
 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
-                             bool registered, SilcIDCacheEntry *ret_entry)
+                             SilcBool registered, SilcIDCacheEntry *ret_entry)
 {
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server;
@@ -163,8 +139,7 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
   SILC_LOG_DEBUG(("Server ID (%s)",
                  silc_id_render(id, SILC_ID_SERVER)));
 
-  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
-                                  &id_cache))
+  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, &id_cache))
     return NULL;
 
   server = (SilcServerEntry)id_cache->context;
@@ -185,7 +160,7 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
 
 SilcServerEntry
 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
-                               bool registered, SilcIDCacheEntry *ret_entry)
+                               SilcBool registered, SilcIDCacheEntry *ret_entry)
 {
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server;
@@ -213,42 +188,36 @@ silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
 
 SilcServerEntry
 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
-                               int port, bool registered,
+                               int port, SilcBool registered,
                                SilcIDCacheEntry *ret_entry)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server = NULL;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
+  const char *host = NULL, *ip = NULL;
 
   SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
 
   if (!silc_idcache_get_all(id_list->servers, &list))
     return NULL;
 
-  if (!silc_idcache_list_first(list, &id_cache)) {
-    silc_idcache_list_free(list);
-    return NULL;
-  }
+  silc_list_start(list);
+  while ((id_cache = silc_list_get(list))) {
+    server = id_cache->context;
+    sock = server->connection;
 
-  while (id_cache) {
-    server = (SilcServerEntry)id_cache->context;
-    sock = (SilcSocketConnection)server->connection;
-
-    if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
-                (sock->ip && !strcasecmp(sock->ip, hostname)))
-       && server->id->port == SILC_SWAB_16(port))
-      break;
+    if (sock && silc_socket_stream_get_info(sock, NULL, &host, &ip, NULL)) {
+      if (((host && !strcasecmp(host, hostname)) ||
+          (ip && !strcasecmp(ip, hostname))) &&
+         server->id->port == SILC_SWAB_16(port))
+       break;
+    }
 
     id_cache = NULL;
     server = NULL;
-
-    if (!silc_idcache_list_next(list, &id_cache))
-      break;
   }
 
-  silc_idcache_list_free(list);
-
   if (server && registered &&
       !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
     return NULL;
@@ -276,8 +245,7 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
 
   SILC_LOG_DEBUG(("Replacing Server ID"));
 
-  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
-                                  &id_cache))
+  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
     return NULL;
 
   server = (SilcServerEntry)id_cache->context;
@@ -285,12 +253,9 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
 
   /* Remove the old entry and add a new one */
 
-  silc_idcache_del_by_id(id_list->servers, (void *)server->id);
-
-  silc_free(server->id);
-  server->id = new_id;
-
-  silc_idcache_add(id_list->servers, name, server->id, server, 0, NULL);
+  silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
+  *server->id = *new_id;
+  silc_idcache_add(id_list->servers, name, server->id, server);
 
   SILC_LOG_DEBUG(("Found"));
 
@@ -303,7 +268,7 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
 {
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->servers, entry)) {
+    if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
       SILC_LOG_DEBUG(("Unknown server, did not delete"));
       return FALSE;
     }
@@ -344,8 +309,7 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
 SilcClientEntry
 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
                       char *userinfo, SilcClientID *id,
-                      SilcServerEntry router, void *connection,
-                      int expire)
+                      SilcServerEntry router, void *connection)
 {
   SilcClientEntry client;
   char *nicknamec = NULL;
@@ -362,20 +326,17 @@ silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
 
   /* Check username. */
   if (username) {
-    char *u = NULL, *h = NULL;
-    silc_parse_userfqdn(username, &u, &h);
+    char u[128 + 1], h[256 + 1];
+    int ret;
+
+    ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
     if (!u)
       return NULL;
-    if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128)) {
-      silc_free(u);
-      silc_free(h);
+    if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
       return NULL;
-    }
-    if (h && !silc_identifier_verify(h, strlen(h), SILC_STRING_UTF8, 256)) {
-      silc_free(u);
-      silc_free(h);
+    if (ret > 1 && !silc_identifier_verify(h, strlen(h),
+                                          SILC_STRING_UTF8, 256))
       return NULL;
-    }
   }
 
   client = silc_calloc(1, sizeof(*client));
@@ -389,7 +350,7 @@ silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
                                           NULL, NULL, NULL, NULL, TRUE);
 
   if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
-                       (void *)client, expire, NULL)) {
+                       (void *)client)) {
     silc_hash_table_free(client->channels);
     silc_free(client);
     silc_free(nicknamec);
@@ -407,7 +368,7 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
   SILC_LOG_DEBUG(("Start"));
 
   if (entry) {
-    if (!silc_idcache_del_by_context(id_list->clients, entry)) {
+    if (!silc_idcache_del_by_context(id_list->clients, entry, NULL /* XXX */)) {
       SILC_LOG_DEBUG(("Unknown client, did not delete"));
       return FALSE;
     }
@@ -435,9 +396,10 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
 
 void silc_idlist_client_destructor(SilcIDCache cache,
                                   SilcIDCacheEntry entry,
-                                  void *context)
+                                  void *dest_context,
+                                  void *app_context)
 {
-  SilcServer server = context;
+  SilcServer server = app_context;
   SilcClientEntry client;
 
   client = (SilcClientEntry)entry->context;
@@ -472,7 +434,7 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
                                        SilcClientEntry **clients,
                                        SilcUInt32 *clients_count)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
 
   SILC_LOG_DEBUG(("Start"));
@@ -481,15 +443,12 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
     return FALSE;
 
   *clients = silc_realloc(*clients,
-                         (silc_idcache_list_count(list) + *clients_count) *
+                         (silc_list_count(list) + *clients_count) *
                          sizeof(**clients));
 
-  silc_idcache_list_first(list, &id_cache);
-  (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-
-  while (silc_idcache_list_next(list, &id_cache))
-    (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-  silc_idcache_list_free(list);
+  silc_list_start(list);
+  while ((id_cache = silc_list_get(list)))
+    (*clients)[(*clients_count)++] = id_cache->context;
 
   SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
 
@@ -505,7 +464,7 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
                                    SilcClientEntry **clients,
                                    SilcUInt32 *clients_count)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   unsigned char hash[SILC_HASH_MAXLEN];
   SilcClientID client_id;
@@ -524,16 +483,12 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
     return FALSE;
 
   *clients = silc_realloc(*clients,
-                         (silc_idcache_list_count(list) + *clients_count) *
+                         (silc_list_count(list) + *clients_count) *
                          sizeof(**clients));
 
-  silc_idcache_list_first(list, &id_cache);
-  (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-
-  while (silc_idcache_list_next(list, &id_cache))
-    (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-
-  silc_idcache_list_free(list);
+  silc_list_start(list);
+  while ((id_cache = silc_list_get(list)))
+    (*clients)[(*clients_count)++] = id_cache->context;
 
   SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
 
@@ -544,7 +499,7 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
 
 SilcClientEntry
 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
-                             bool registered, SilcIDCacheEntry *ret_entry)
+                             SilcBool registered, SilcIDCacheEntry *ret_entry)
 {
   SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry client;
@@ -555,14 +510,8 @@ silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
   SILC_LOG_DEBUG(("Client ID (%s)",
                  silc_id_render(id, SILC_ID_CLIENT)));
 
-  /* Do extended search since the normal ID comparison function for
-     Client ID's compares only the hash from the Client ID and not the
-     entire ID. The silc_hash_client_id_compare compares the entire
-     Client ID as we want to find one specific Client ID. */
-  if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
-                                      NULL, NULL,
-                                      silc_hash_client_id_compare, NULL,
-                                      &id_cache))
+  /* Find the exact client with the exact Client ID */
+  if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, &id_cache))
     return NULL;
 
   client = (SilcClientEntry)id_cache->context;
@@ -603,21 +552,15 @@ silc_idlist_replace_client_id(SilcServer server,
       return NULL;
   }
 
-  /* Do extended search since the normal ID comparison function for
-     Client ID's compares only the hash from the Client ID and not the
-     entire ID. The silc_hash_client_id_compare compares the entire
-     Client ID as we want to find one specific Client ID. */
-  if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
-                                      NULL, NULL,
-                                      silc_hash_client_id_compare, NULL,
-                                      &id_cache))
+  /* Find exact client with exact Client ID */
+  if (!silc_idcache_find_by_id_one(id_list->clients, old_id, &id_cache))
     return NULL;
 
   client = (SilcClientEntry)id_cache->context;
 
   /* Remove the old entry and add a new one */
 
-  if (!silc_idcache_del_by_context(id_list->clients, client))
+  if (!silc_idcache_del_by_context(id_list->clients, client, server))
     return NULL;
 
   /* Check if anyone is watching old nickname */
@@ -625,9 +568,8 @@ silc_idlist_replace_client_id(SilcServer server,
     silc_server_check_watcher_list(server, client, nickname,
                                   SILC_NOTIFY_TYPE_NICK_CHANGE);
 
-  silc_free(client->id);
   silc_free(client->nickname);
-  client->id = new_id;
+  *client->id = *new_id;
   client->nickname = nickname ? strdup(nickname) : NULL;
 
   /* Check if anyone is watching new nickname */
@@ -636,7 +578,7 @@ silc_idlist_replace_client_id(SilcServer server,
                                   SILC_NOTIFY_TYPE_NICK_CHANGE);
 
   if (!silc_idcache_add(id_list->clients, nicknamec, client->id,
-                       client, 0, NULL))
+                       client))
     return NULL;
 
   SILC_LOG_DEBUG(("Replaced"));
@@ -657,8 +599,8 @@ silc_idlist_replace_client_id(SilcServer server,
 SilcChannelEntry
 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
                        SilcChannelID *id, SilcServerEntry router,
-                       SilcCipher channel_key, SilcHmac hmac,
-                       int expire)
+                       SilcCipher send_key, SilcCipher receive_key,
+                       SilcHmac hmac)
 {
   SilcChannelEntry channel;
   char *channel_namec = NULL;
@@ -678,7 +620,8 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
   channel->mode = mode;
   channel->id = id;
   channel->router = router;
-  channel->channel_key = channel_key;
+  channel->send_key = send_key;
+  channel->receive_key = receive_key;
   channel->hmac = hmac;
   channel->created = channel->updated = time(0);
   if (!channel->hmac)
@@ -691,7 +634,7 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
                                             NULL, NULL, NULL, TRUE);
 
   if (!silc_idcache_add(id_list->channels, channel_namec,
-                       (void *)channel->id, (void *)channel, expire, NULL)) {
+                       (void *)channel->id, (void *)channel /*XXX, expire */)) {
     silc_hmac_free(channel->hmac);
     silc_hash_table_free(channel->user_list);
     silc_free(channel);
@@ -726,7 +669,7 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
 {
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->channels, entry)) {
+    if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
       SILC_LOG_DEBUG(("Unknown channel, did not delete"));
       return FALSE;
     }
@@ -750,8 +693,10 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
     if (entry->ban_list)
       silc_hash_table_free(entry->ban_list);
 
-    if (entry->channel_key)
-      silc_cipher_free(entry->channel_key);
+    if (entry->send_key)
+      silc_cipher_free(entry->send_key);
+    if (entry->receive_key)
+      silc_cipher_free(entry->receive_key);
     if (entry->key) {
       memset(entry->key, 0, entry->key_len / 8);
       silc_free(entry->key);
@@ -855,12 +800,9 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
 
   /* Remove the old entry and add a new one */
 
-  silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
-
-  silc_free(channel->id);
-  channel->id = new_id;
-
-  silc_idcache_add(id_list->channels, name, channel->id, channel, 0, NULL);
+  silc_idcache_del_by_id(id_list->channels, (void *)channel->id, NULL);
+  *channel->id = *new_id;
+  silc_idcache_add(id_list->channels, name, channel->id, channel);
 
   SILC_LOG_DEBUG(("Replaced"));
 
@@ -877,7 +819,7 @@ SilcChannelEntry *
 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
                         SilcUInt32 *channels_count)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry *channels = NULL;
   int i = 0;
@@ -888,16 +830,12 @@ silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
     if (!silc_idcache_get_all(id_list->channels, &list))
       return NULL;
 
-    channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
+    channels = silc_calloc(silc_list_count(list), sizeof(*channels));
 
     i = 0;
-    silc_idcache_list_first(list, &id_cache);
-    channels[i++] = (SilcChannelEntry)id_cache->context;
-
-    while (silc_idcache_list_next(list, &id_cache))
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list)))
       channels[i++] = (SilcChannelEntry)id_cache->context;
-
-    silc_idcache_list_free(list);
   } else {
     if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
       return NULL;
index 0c4d0a60808c4b1a885893e93c259bb686734a17..e6d1ce47514c0851fedb143cd210ee7524d94397 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 #ifndef IDLIST_H
 #define IDLIST_H
 
-/* Forward declarations */
-typedef struct SilcServerEntryStruct *SilcServerEntry;
-typedef struct SilcClientEntryStruct *SilcClientEntry;
-typedef struct SilcChannelEntryStruct *SilcChannelEntry;
+#include "serverconfig.h"
 
 /* Context for holding cache information to periodically purge
    the cache. */
@@ -40,18 +37,6 @@ typedef struct {
   SilcTask task;
 } *SilcServerChannelRekey;
 
-/* Generic rekey context for connections */
-typedef struct {
-  /* Current sending encryption key, provided for re-key. The `pfs'
-     is TRUE if the Perfect Forward Secrecy is performed in re-key. */
-  unsigned char *send_enc_key;
-  SilcUInt32 enc_key_len;
-  int ske_group;
-  bool pfs;
-  SilcUInt32 timeout;
-  void *context;
-} *SilcServerRekey;
-
 /* ID List Entry status flags. */
 typedef SilcUInt8 SilcIDListStatus;
 #define SILC_IDLIST_STATUS_NONE         0x00  /* No status */
@@ -80,36 +65,23 @@ typedef SilcUInt8 SilcIDListStatus;
    Note that some of the fields may be NULL.
 
 */
-typedef struct {
-  /* Send and receive symmetric keys */
-  SilcCipher send_key;
-  SilcCipher receive_key;
-
-  /* HMAC */
-  SilcHmac hmac_send;
-  SilcHmac hmac_receive;
-
-  /* Packet sequence numbers */
-  SilcUInt32 psn_send;
-  SilcUInt32 psn_receive;
-
-  /* Hash selected in the SKE protocol, NULL if not needed at all */
+struct SilcIDListDataObject {
+  SilcConnectionType conn_type;      /* Connection type */
+  SilcServerConnection sconn;       /* Connection context */
+  SilcSKERekeyMaterial rekey;       /* Rekey material */
   SilcHash hash;
 
   /* Public key */
   SilcPublicKey public_key;
   unsigned char fingerprint[20];
 
-  /* Re-key context */
-  SilcServerRekey rekey;
-
   long last_receive;           /* Time last received data */
   long last_sent;              /* Time last sent data */
 
   unsigned long created;       /* Time when entry was created */
 
   SilcIDListStatus status;     /* Status mask of the entry */
-} *SilcIDListData, SilcIDListDataStruct;
+};
 
 /*
    SILC Server entry object.
@@ -410,7 +382,7 @@ struct SilcClientEntryStruct {
        ID of the channel. This includes all the information SILC will ever
        need.
 
-   bool global_users
+   SilcBool global_users
 
        Boolean value to tell whether there are users outside this server
        on this channel. This is set to TRUE if router sends message to
@@ -452,7 +424,8 @@ struct SilcClientEntryStruct {
        whose cell this channel belongs to. This is used to route messages
        to this channel.
 
-   SilcCipher channel_key
+   SilcCipher send_key
+   SilcCipher receive_key
 
        The key of the channel (the cipher actually).
 
@@ -498,7 +471,8 @@ struct SilcChannelEntryStruct {
   SilcServerEntry router;
 
   /* Channel keys */
-  SilcCipher channel_key;
+  SilcCipher send_key;
+  SilcCipher receive_key;
   unsigned char *key;
   SilcUInt32 key_len;
   SilcHmac hmac;
@@ -549,11 +523,11 @@ struct SilcChannelEntryStruct {
    channel entry).
 
 */
-typedef struct SilcIDListStruct {
+struct SilcIDListStruct {
   SilcIDCache servers;
   SilcIDCache clients;
   SilcIDCache channels;
-} *SilcIDList;
+};
 
 /*
    ID Entry for Unknown connections.
@@ -569,12 +543,19 @@ typedef struct SilcIDListStruct {
 typedef struct {
   /* Generic data structure. DO NOT add anything before this! */
   SilcIDListDataStruct data;
+  SilcServerConfigRef cconfig;
+  SilcServerConfigRef sconfig;
+  SilcServerConfigRef rconfig;
+  SilcServer server;
+  const char *hostname;
+  const char *ip;
+  SilcUInt16 port;
 } *SilcUnknownEntry;
 
 /* Prototypes */
 void silc_idlist_add_data(void *entry, SilcIDListData idata);
 void silc_idlist_del_data(void *entry);
-SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge);
+SILC_TASK_CALLBACK(silc_idlist_purge);
 SilcServerEntry
 silc_idlist_add_server(SilcIDList id_list,
                       char *server_name, int server_type,
@@ -582,13 +563,13 @@ silc_idlist_add_server(SilcIDList id_list,
                       void *connection);
 SilcServerEntry
 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
-                             bool registered, SilcIDCacheEntry *ret_entry);
+                             SilcBool registered, SilcIDCacheEntry *ret_entry);
 SilcServerEntry
 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
-                               bool registered, SilcIDCacheEntry *ret_entry);
+                               SilcBool registered, SilcIDCacheEntry *ret_entry);
 SilcServerEntry
 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
-                               int port, bool registered,
+                               int port, SilcBool registered,
                                SilcIDCacheEntry *ret_entry);
 SilcServerEntry
 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
@@ -597,8 +578,7 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry);
 SilcClientEntry
 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
                       char *userinfo, SilcClientID *id,
-                      SilcServerEntry router, void *connection,
-                      int expire);
+                      SilcServerEntry router, void *connection);
 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry);
 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
                                        char *server,
@@ -610,19 +590,20 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
                                    SilcUInt32 *clients_count);
 SilcClientEntry
 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
-                             bool registered, SilcIDCacheEntry *ret_entry);
+                             SilcBool registered, SilcIDCacheEntry *ret_entry);
 SilcClientEntry
 silc_idlist_replace_client_id(SilcServer server,
                              SilcIDList id_list, SilcClientID *old_id,
                              SilcClientID *new_id, const char *nickname);
 void silc_idlist_client_destructor(SilcIDCache cache,
                                   SilcIDCacheEntry entry,
-                                  void *context);
+                                  void *dest_context,
+                                  void *app_context);
 SilcChannelEntry
 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
                        SilcChannelID *id, SilcServerEntry router,
-                       SilcCipher channel_key, SilcHmac hmac,
-                       int expire);
+                       SilcCipher send_key, SilcCipher receive_key,
+                       SilcHmac hmac);
 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry);
 SilcChannelEntry
 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
index 3a692fd3b688bd036202ab733d1c141ab0676b9c..313004f8330efaa3b62ddddeed7e66ac77c24d9e 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   GNU General Public License for more details.
 
 */
-/*
- * Server packet routines to handle received packets.
- */
-/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
 /* Received notify packet. Server can receive notify packets from router.
    Server then relays the notify messages to clients if needed. */
 
-void silc_server_notify(SilcServer server,
-                       SilcSocketConnection sock,
-                       SilcPacketContext *packet)
+static void silc_server_notify_process(SilcServer server,
+                                      SilcPacketStream sock,
+                                      SilcPacket packet,
+                                      SilcBuffer buffer)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcNotifyPayload payload;
   SilcNotifyType type;
   SilcArgumentPayload args;
-  SilcChannelID *channel_id = NULL, *channel_id2;
-  SilcClientID *client_id, *client_id2;
-  SilcServerID *server_id;
-  SilcIdType id_type;
+  SilcChannelID channel_id;
+  SilcID id, id2;
   SilcChannelEntry channel = NULL;
   SilcClientEntry client = NULL, client2 = NULL;
   SilcServerEntry server_entry = NULL;
@@ -46,11 +42,11 @@ void silc_server_notify(SilcServer server,
   SilcIDCacheEntry cache = NULL;
   SilcHashTableList htl;
   SilcUInt32 mode;
-  unsigned char *tmp;
-  SilcUInt32 tmp_len;
-  bool local;
+  unsigned char *tmp, *tmp2;
+  SilcUInt32 tmp_len, tmp2_len;
+  SilcBool local, ret;
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+  if (idata->conn_type == SILC_CONN_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER || !packet->dst_id) {
     SILC_LOG_DEBUG(("Bad notify packet received"));
     return;
@@ -60,7 +56,7 @@ void silc_server_notify(SilcServer server,
      before processing it. */
   if (packet->dst_id_type == SILC_ID_CLIENT) {
     SilcIDListData idata;
-    SilcSocketConnection dst_sock;
+    SilcPacketStream dst_sock;
 
     /* Get the route to the client */
     dst_sock = silc_server_get_client_route(server, packet->dst_id,
@@ -68,14 +64,11 @@ void silc_server_notify(SilcServer server,
                                            &idata, NULL);
     if (dst_sock)
       /* Relay the packet */
-      silc_server_relay_packet(server, dst_sock, idata->send_key,
-                              idata->hmac_send, idata->psn_send++,
-                              packet, TRUE);
+      silc_server_packet_route(server, dst_sock, packet);
   }
 
   /* Parse the Notify Payload */
-  payload = silc_notify_payload_parse(packet->buffer->data,
-                                     packet->buffer->len);
+  payload = silc_notify_payload_parse(buffer->data, silc_buffer_len(buffer));
   if (!payload)
     return;
 
@@ -84,37 +77,35 @@ void silc_server_notify(SilcServer server,
      the router is buggy. If this packet is coming from router then it must
      have the broadcast flag set already and we won't do anything. */
   if (server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      idata->conn_type == SILC_CONN_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received Notify packet"));
     if (packet->dst_id_type == SILC_ID_CHANNEL) {
       /* Packet is destined to channel */
-      channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                                 packet->dst_id_type);
-      if (!channel_id)
+      if (!silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                         packet->dst_id_type, &channel_id,
+                         sizeof(channel_id)))
        goto out;
 
       silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server),
                                   packet->type, packet->flags |
                                   SILC_PACKET_FLAG_BROADCAST,
-                                  channel_id, SILC_ID_CHANNEL,
-                                  packet->buffer->data,
-                                  packet->buffer->len, FALSE);
-      silc_server_backup_send_dest(server, sock->user_data,
+                                  &channel_id, SILC_ID_CHANNEL,
+                                  buffer->data, silc_buffer_len(buffer));
+      silc_server_backup_send_dest(server, (SilcServerEntry)idata,
                                   packet->type, packet->flags,
-                                  channel_id, SILC_ID_CHANNEL,
-                                  packet->buffer->data, packet->buffer->len,
+                                  &channel_id, SILC_ID_CHANNEL,
+                                  buffer->data, silc_buffer_len(buffer),
                                   FALSE, TRUE);
     } else {
       /* Packet is destined to client or server */
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              packet->type,
                              packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                             packet->buffer->data, packet->buffer->len,
-                             FALSE);
-      silc_server_backup_send(server, sock->user_data,
+                             buffer->data, silc_buffer_len(buffer));
+      silc_server_backup_send(server, (SilcServerEntry)idata,
                              packet->type, packet->flags,
-                             packet->buffer->data, packet->buffer->len,
+                             buffer->data, silc_buffer_len(buffer),
                              FALSE, TRUE);
     }
   }
@@ -131,70 +122,56 @@ void silc_server_notify(SilcServer server,
      */
     SILC_LOG_DEBUG(("JOIN notify"));
 
-    if (channel_id)
-      silc_free(channel_id);
-
     /* Get Channel ID */
-    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp)
-      goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id)
+    if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get channel entry */
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              SILC_ID_GET_ID(id), NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
-    silc_free(channel_id);
 
     /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!client_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* If the the client is not in local list we check global list (ie. the
        channel will be global channel) and if it does not exist then create
        entry for the client. */
     client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, server->server_type,
+                                          SILC_ID_GET_ID(id),
+                                          server->server_type,
                                           &cache);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list,
-                                            client_id, server->server_type,
+                                            SILC_ID_GET_ID(id),
+                                            server->server_type,
                                             &cache);
       if (!client) {
        /* If router did not find the client the it is bogus */
-       if (server->server_type != SILC_SERVER) {
-         silc_free(client_id);
+       if (server->server_type != SILC_SERVER)
          goto out;
-       }
 
        client =
          silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
-                                silc_id_dup(client_id, SILC_ID_CLIENT),
-                                sock->user_data, NULL, 0);
+                                silc_id_dup(SILC_ID_GET_ID(id),
+                                            SILC_ID_CLIENT),
+                                (SilcServerEntry)idata, NULL);
        if (!client) {
          SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-         silc_free(client_id);
          goto out;
        }
 
        client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       }
     }
-    silc_free(client_id);
 
     /* Do not process the notify if the client is not registered */
     if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
@@ -209,11 +186,11 @@ void silc_server_notify(SilcServer server,
 
     /* Send to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type,
-                                      FALSE, TRUE, packet->buffer->data,
-                                      packet->buffer->len, FALSE);
+                                      FALSE, TRUE, buffer->data,
+                                      silc_buffer_len(buffer));
 
     if (server->server_type != SILC_ROUTER &&
-       sock->type == SILC_SOCKET_TYPE_ROUTER)
+       idata->conn_type == SILC_CONN_ROUTER)
       /* The channel is global now */
       channel->global_users = TRUE;
 
@@ -222,11 +199,13 @@ void silc_server_notify(SilcServer server,
     /* JOIN the global client to the channel (local clients (if router
        created the channel) is joined in the pending JOIN command). */
     chl = silc_calloc(1, sizeof(*chl));
+    if (!chl)
+      goto out;
     chl->client = client;
     chl->channel = channel;
 
     if (server->server_type != SILC_ROUTER ||
-       sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       idata->conn_type == SILC_CONN_ROUTER) {
       /* If founder auth is set, first client is not automatically founder. */
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
        /* If this is the first one on the channel then it is the founder of
@@ -245,13 +224,9 @@ void silc_server_notify(SilcServer server,
     channel->user_count++;
     channel->disabled = FALSE;
 
-    /* Make sure we don't expire clients that are on channel */
-    if (cache)
-      cache->expire = 0;
-
     /* Update statistics */
     if (server->server_type == SILC_ROUTER) {
-      if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+      if (idata->conn_type != SILC_CONN_ROUTER)
        server->stat.cell_chanclients++;
       server->stat.chanclients++;
     }
@@ -264,52 +239,36 @@ void silc_server_notify(SilcServer server,
      */
     SILC_LOG_DEBUG(("LEAVE notify"));
 
-    if (!channel_id) {
-      channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                                 packet->dst_id_type);
-      if (!channel_id)
-       goto out;
-    }
+    if (!silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                       packet->dst_id_type, &channel_id,
+                       sizeof(channel_id)))
+      goto out;
 
     /* Get channel entry */
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            &channel_id, NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              &channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
 
     /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp) {
-      silc_free(channel_id);
-      goto out;
-    }
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!client_id) {
-      silc_free(channel_id);
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
-    }
 
     /* Get client entry */
     client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, TRUE, NULL);
+                                          SILC_ID_GET_ID(id), TRUE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list,
-                                            client_id, TRUE, NULL);
-      if (!client) {
-       silc_free(client_id);
-       silc_free(channel_id);
+                                            SILC_ID_GET_ID(id), TRUE, NULL);
+      if (!client)
        goto out;
-      }
     }
-    silc_free(client_id);
-    silc_free(channel_id);
 
     /* Check if on channel */
     if (!silc_server_client_on_channel(client, channel, NULL))
@@ -317,8 +276,8 @@ void silc_server_notify(SilcServer server,
 
     /* Send the leave notify to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type,
-                                      FALSE, TRUE, packet->buffer->data,
-                                      packet->buffer->len, FALSE);
+                                      FALSE, TRUE, buffer->data,
+                                      silc_buffer_len(buffer));
 
     /* Remove the user from channel */
     silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
@@ -331,30 +290,23 @@ void silc_server_notify(SilcServer server,
     SILC_LOG_DEBUG(("SIGNOFF notify"));
 
     /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!client_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get client entry */
     client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, TRUE, &cache);
+                                          SILC_ID_GET_ID(id), TRUE, &cache);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list,
-                                            client_id, TRUE, &cache);
-      if (!client) {
-       silc_free(client_id);
+                                            SILC_ID_GET_ID(id), TRUE, &cache);
+      if (!client)
        goto out;
-      }
     }
-    silc_free(client_id);
 
     /* Get signoff message */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (tmp_len > 128)
-      tmp = NULL;
+      tmp_len = 128;
 
     /* Update statistics */
     server->stat.clients--;
@@ -385,7 +337,6 @@ void silc_server_notify(SilcServer server,
     client->mode = 0;
     client->router = NULL;
     client->connection = NULL;
-    cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -396,55 +347,43 @@ void silc_server_notify(SilcServer server,
     SILC_LOG_DEBUG(("TOPIC SET notify"));
 
     /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-    if (!client_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get client entry */
-    if (id_type == SILC_ID_CLIENT) {
+    if (id.type == SILC_ID_CLIENT) {
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, TRUE, &cache);
+                                            SILC_ID_GET_ID(id), TRUE, &cache);
       if (!client) {
        client = silc_idlist_find_client_by_id(server->local_list,
-                                              client_id, TRUE, &cache);
-       if (!client) {
-         silc_free(client_id);
+                                              SILC_ID_GET_ID(id),
+                                              TRUE, &cache);
+       if (!client)
          goto out;
-       }
       }
-      silc_free(client_id);
     }
 
     /* Get the topic */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp) {
-      silc_free(channel_id);
+    if (!tmp)
       goto out;
-    }
 
-    if (!channel_id) {
-      channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                                 packet->dst_id_type);
-      if (!channel_id)
-       goto out;
-    }
+    if (!silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                       packet->dst_id_type, &channel_id,
+                       sizeof(channel_id)))
+      goto out;
 
     /* Get channel entry */
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            &channel_id, NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              &channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
-    silc_free(channel_id);
 
     if (channel->topic && !strcmp(channel->topic, tmp)) {
       SILC_LOG_DEBUG(("Topic is already set and same"));
@@ -469,8 +408,8 @@ void silc_server_notify(SilcServer server,
 
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
-                                      FALSE, TRUE, packet->buffer->data,
-                                      packet->buffer->len, FALSE);
+                                      FALSE, TRUE, buffer->data,
+                                      silc_buffer_len(buffer));
     break;
 
   case SILC_NOTIFY_TYPE_NICK_CHANGE:
@@ -478,60 +417,50 @@ void silc_server_notify(SilcServer server,
       /*
        * Distribute the notify to local clients on the channel
        */
-      unsigned char *id, *id2;
       char *nickname;
       SilcUInt32 nickname_len;
 
       SILC_LOG_DEBUG(("NICK CHANGE notify"));
 
       /* Get old client ID */
-      id = silc_argument_get_arg_type(args, 1, &tmp_len);
-      if (!id)
-       goto out;
-      client_id = silc_id_payload_parse_id(id, tmp_len, NULL);
-      if (!client_id)
+      if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
        goto out;
 
       /* Get new client ID */
-      id2 = silc_argument_get_arg_type(args, 2, &tmp_len);
-      if (!id2)
-       goto out;
-      client_id2 = silc_id_payload_parse_id(id2, tmp_len, NULL);
-      if (!client_id2) {
-       silc_free(client_id);
+      if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
        goto out;
-      }
 
       SILC_LOG_DEBUG(("Old Client ID id(%s)",
-                     silc_id_render(client_id, SILC_ID_CLIENT)));
+                     silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CLIENT)));
       SILC_LOG_DEBUG(("New Client ID id(%s)",
-                     silc_id_render(client_id2, SILC_ID_CLIENT)));
+                     silc_id_render(SILC_ID_GET_ID(id2), SILC_ID_CLIENT)));
 
       /* From protocol version 1.1 we also get the new nickname */
       nickname = silc_argument_get_arg_type(args, 3, &nickname_len);;
 
       /* Replace the Client ID */
       client = silc_idlist_replace_client_id(server,
-                                            server->global_list, client_id,
-                                            client_id2, nickname);
+                                            server->global_list,
+                                            SILC_ID_GET_ID(id),
+                                            SILC_ID_GET_ID(id2), nickname);
       if (!client)
        client = silc_idlist_replace_client_id(server,
-                                              server->local_list, client_id,
-                                              client_id2, nickname);
+                                              server->local_list,
+                                              SILC_ID_GET_ID(id),
+                                              SILC_ID_GET_ID(id2), nickname);
 
       if (client) {
        /* Send the NICK_CHANGE notify type to local clients on the channels
           this client is joined to. */
+       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+       tmp2 = silc_argument_get_arg_type(args, 2, &tmp2_len);
        silc_server_send_notify_on_channels(server, client, client,
                                            SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
-                                           id, tmp_len, id2, tmp_len,
+                                           tmp, tmp_len, tmp2, tmp2_len,
                                            nickname, nickname ?
                                            nickname_len : 0);
       }
 
-      silc_free(client_id);
-      if (!client)
-       silc_free(client_id2);
       break;
     }
 
@@ -543,48 +472,38 @@ void silc_server_notify(SilcServer server,
     SILC_LOG_DEBUG(("CMODE CHANGE notify"));
 
     /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-    if (!client_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get client entry */
-    if (id_type == SILC_ID_CLIENT) {
+    if (id.type == SILC_ID_CLIENT) {
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, TRUE, &cache);
+                                            SILC_ID_GET_ID(id), TRUE, &cache);
       if (!client) {
        client = silc_idlist_find_client_by_id(server->local_list,
-                                              client_id, TRUE, &cache);
-       if (!client) {
-         silc_free(client_id);
+                                              SILC_ID_GET_ID(id),
+                                              TRUE, &cache);
+       if (!client)
          goto out;
-       }
       }
     }
-    silc_free(client_id);
 
-    if (!channel_id) {
-      channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                                 packet->dst_id_type);
-      if (!channel_id)
-       goto out;
-    }
+    if (!silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                       packet->dst_id_type, &channel_id,
+                       sizeof(channel_id)))
+      goto out;
 
     /* Get channel entry */
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            &channel_id, NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              &channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
-    silc_free(channel_id);
 
     /* Get the mode */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
@@ -624,8 +543,8 @@ void silc_server_notify(SilcServer server,
        if (channel->founder_key)
          silc_pkcs_public_key_free(channel->founder_key);
        channel->founder_key = NULL;
-       silc_pkcs_public_key_payload_decode(tmp, tmp_len,
-                                           &channel->founder_key);
+       silc_public_key_payload_decode(tmp, tmp_len,
+                                      &channel->founder_key);
       }
 
       /* Check also for channel public key list */
@@ -654,7 +573,7 @@ void silc_server_notify(SilcServer server,
          SILC_PUT32_MSB(channel->user_limit, ulimit);
        silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                           SILC_NOTIFY_TYPE_CMODE_CHANGE, 8,
-                                          sidp->data, sidp->len,
+                                          sidp->data, silc_buffer_len(sidp),
                                           mask, 4,
                                           channel->cipher,
                                           channel->cipher ?
@@ -666,7 +585,8 @@ void silc_server_notify(SilcServer server,
                                           channel->passphrase ?
                                           strlen(channel->passphrase) : 0,
                                           NULL, 0,
-                                          chpklist->data, chpklist->len,
+                                          chpklist->data,
+                                          silc_buffer_len(chpklist),
                                           (channel->mode &
                                            SILC_CHANNEL_MODE_ULIMIT ?
                                            ulimit : NULL),
@@ -719,7 +639,7 @@ void silc_server_notify(SilcServer server,
        silc_hash_table_list(channel->user_list, &htl);
        while (silc_hash_table_get(&htl, NULL, (void *)&chl))
          if (chl->mode & SILC_CHANNEL_UMODE_CHANFO &&
-             chl->client->router != sock->user_data) {
+             chl->client->router != (SilcServerEntry)idata) {
            SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
            silc_server_send_notify_cmode(server, sock, FALSE, channel,
                                          channel->mode, server->id,
@@ -782,8 +702,8 @@ void silc_server_notify(SilcServer server,
        silc_pkcs_public_key_free(channel->founder_key);
       channel->founder_key = NULL;
       SILC_LOG_DEBUG(("Founder public key received"));
-      if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len,
-                                              &channel->founder_key)) {
+      if (!silc_public_key_payload_decode(tmp, tmp_len,
+                                         &channel->founder_key)) {
        SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
        mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
        silc_server_send_notify_cmode(server, sock, FALSE, channel,
@@ -838,8 +758,8 @@ void silc_server_notify(SilcServer server,
 
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
-                                      FALSE, TRUE, packet->buffer->data,
-                                      packet->buffer->len, FALSE);
+                                      FALSE, TRUE, buffer->data,
+                                      silc_buffer_len(buffer));
 
     /* Change mode */
     channel->mode = mode;
@@ -866,82 +786,66 @@ void silc_server_notify(SilcServer server,
        * Distribute the notify to local clients on the channel
        */
       SilcChannelClientEntry chl2 = NULL;
-      bool notify_sent = FALSE;
+      SilcBool notify_sent = FALSE;
 
       SILC_LOG_DEBUG(("CUMODE CHANGE notify"));
 
       /* Get client ID */
-      tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-      if (!tmp)
-       goto out;
-      client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-      if (!client_id)
+      if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
        goto out;
 
       /* Get client entry */
-      if (id_type == SILC_ID_CLIENT) {
+      if (id.type == SILC_ID_CLIENT) {
        client = silc_idlist_find_client_by_id(server->global_list,
-                                              client_id, TRUE, &cache);
+                                              SILC_ID_GET_ID(id),
+                                              TRUE, &cache);
        if (!client) {
          client = silc_idlist_find_client_by_id(server->local_list,
-                                                client_id, TRUE, &cache);
-         if (!client) {
-           silc_free(client_id);
+                                                SILC_ID_GET_ID(id),
+                                                TRUE, &cache);
+         if (!client)
            goto out;
-         }
        }
       }
-      silc_free(client_id);
 
-      if (!channel_id) {
-       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                                   packet->dst_id_type);
-       if (!channel_id)
-         goto out;
-      }
+      if (!silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                         packet->dst_id_type, &channel_id,
+                         sizeof(channel_id)))
+       goto out;
 
       /* Get channel entry */
       channel = silc_idlist_find_channel_by_id(server->global_list,
-                                              channel_id, NULL);
+                                              &channel_id, NULL);
       if (!channel) {
        channel = silc_idlist_find_channel_by_id(server->local_list,
-                                                channel_id, NULL);
+                                                &channel_id, NULL);
        if (!channel) {
          SILC_LOG_DEBUG(("Notify for unknown channel"));
-         silc_free(channel_id);
          goto out;
        }
       }
 
       /* Get the mode */
       tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-      if (!tmp) {
-       silc_free(channel_id);
+      if (!tmp)
        goto out;
-      }
 
       SILC_GET32_MSB(mode, tmp);
 
       /* Get target client */
-      tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-      if (!tmp)
-       goto out;
-      client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-      if (!client_id)
+      if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
        goto out;
 
       /* Get client entry */
       client2 = silc_idlist_find_client_by_id(server->global_list,
-                                             client_id, TRUE, NULL);
+                                             SILC_ID_GET_ID(id), TRUE, NULL);
       if (!client2) {
        client2 = silc_idlist_find_client_by_id(server->local_list,
-                                               client_id, TRUE, NULL);
-       if (!client2) {
-         silc_free(client_id);
+                                               SILC_ID_GET_ID(id),
+                                               TRUE, NULL);
+       if (!client2)
          goto out;
-       }
       }
-      silc_free(client_id);
 
       if (client) {
        /* Check that sender is on channel */
@@ -1023,8 +927,8 @@ void silc_server_notify(SilcServer server,
        if (channel->founder_key) {
          /* Get public key that must be present in notify */
          tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
-         if (!tmp || !silc_pkcs_public_key_payload_decode(tmp, tmp_len,
-                                                          &founder_key)) {
+         if (!tmp || !silc_public_key_payload_decode(tmp, tmp_len,
+                                                     &founder_key)) {
            chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
            SILC_LOG_DEBUG(("Founder public key not present"));
            silc_server_force_cumode_change(server, sock, channel, chl, mode);
@@ -1079,10 +983,9 @@ void silc_server_notify(SilcServer server,
       if (!notify_sent)
        silc_server_packet_send_to_channel(server, sock, channel,
                                           packet->type,
-                                          FALSE, TRUE, packet->buffer->data,
-                                          packet->buffer->len, FALSE);
+                                          FALSE, TRUE, buffer->data,
+                                          silc_buffer_len(buffer));
 
-      silc_free(channel_id);
       break;
     }
 
@@ -1094,64 +997,20 @@ void silc_server_notify(SilcServer server,
     SILC_LOG_DEBUG(("INVITE notify"));
 
     /* Get Channel ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get channel entry */
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              SILC_ID_GET_ID(id), NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
-    silc_free(channel_id);
-
-#if 0 /* These aren't actually used anywhere or needed, since this
-        notify is for handling the invite list (direct invite
-        goes to client and is not handled here at all). */
-
-    /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!client_id)
-      goto out;
-
-    /* Get client entry */
-    client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, TRUE, &cache);
-    if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list,
-                                            client_id, TRUE, &cache);
-      if (!client) {
-       silc_free(client_id);
-       goto out;
-      }
-    }
-    silc_free(client_id);
-
-    /* Get user's channel entry and check that inviting is allowed. */
-    if (server->server_type == SILC_ROUTER) {
-      if (!silc_server_client_on_channel(client, channel, &chl))
-        goto out;
-      if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
-         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
-         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
-        SILC_LOG_DEBUG(("Inviting is not allowed"));
-        goto out;
-      }
-    }
-#endif
 
     /* Get the invite action */
     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
@@ -1189,8 +1048,8 @@ void silc_server_notify(SilcServer server,
       if (server->server_type == SILC_ROUTER)
        silc_server_packet_send_to_channel(server, sock, channel,
                                           packet->type, FALSE, FALSE,
-                                          packet->buffer->data,
-                                          packet->buffer->len, FALSE);
+                                          buffer->data,
+                                          silc_buffer_len(buffer));
     }
 
     break;
@@ -1203,58 +1062,50 @@ void silc_server_notify(SilcServer server,
 
     SILC_LOG_DEBUG(("CHANNEL CHANGE"));
 
-    if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+    if (idata->conn_type != SILC_CONN_ROUTER)
       break;
 
     /* Get the old Channel ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get the channel entry */
     channel = silc_idlist_find_channel_by_id(server->local_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->global_list,
-                                              channel_id, NULL);
+                                              SILC_ID_GET_ID(id), NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
 
     /* Send the notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type,
-                                      FALSE, TRUE, packet->buffer->data,
-                                      packet->buffer->len, FALSE);
+                                      FALSE, TRUE, buffer->data,
+                                      silc_buffer_len(buffer));
 
     /* Get the new Channel ID */
-    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp)
-      goto out;
-    channel_id2 = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id2)
+    if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
       goto out;
 
     SILC_LOG_DEBUG(("Old Channel ID id(%s)",
-                   silc_id_render(channel_id, SILC_ID_CHANNEL)));
+                   silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
     SILC_LOG_DEBUG(("New Channel ID id(%s)",
-                   silc_id_render(channel_id2, SILC_ID_CHANNEL)));
+                   silc_id_render(SILC_ID_GET_ID(id2), SILC_ID_CHANNEL)));
 
     /* Replace the Channel ID */
-    if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
-                                       channel_id2))
-      if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
-                                         channel_id2)) {
-       silc_free(channel_id2);
-       channel_id2 = NULL;
-      }
-
-    if (channel_id2) {
+    ret = TRUE;
+    if (!silc_idlist_replace_channel_id(server->local_list,
+                                       SILC_ID_GET_ID(id),
+                                       SILC_ID_GET_ID(id2)))
+      if (!silc_idlist_replace_channel_id(server->global_list,
+                                         SILC_ID_GET_ID(id),
+                                         SILC_ID_GET_ID(id2)))
+       ret = FALSE;
+
+    if (ret) {
       SilcBuffer modes = NULL, users = NULL, users_modes = NULL;
 
       /* Re-announce this channel which ID was changed. */
@@ -1271,7 +1122,7 @@ void silc_server_notify(SilcServer server,
        silc_buffer_push(users, users->data - users->head);
        silc_server_packet_send(server, sock,
                                SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users->data, users->len, FALSE);
+                               users->data, silc_buffer_len(users));
        silc_buffer_free(users);
       }
       if (modes) {
@@ -1279,7 +1130,7 @@ void silc_server_notify(SilcServer server,
        silc_server_packet_send_dest(server, sock,
                                     SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                     channel->id, SILC_ID_CHANNEL,
-                                    modes->data, modes->len, FALSE);
+                                    modes->data, silc_buffer_len(modes));
        silc_buffer_free(modes);
       }
       if (users_modes) {
@@ -1288,7 +1139,7 @@ void silc_server_notify(SilcServer server,
                                     SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                     channel->id, SILC_ID_CHANNEL,
                                     users_modes->data,
-                                    users_modes->len, FALSE);
+                                    silc_buffer_len(users_modes));
        silc_buffer_free(users_modes);
       }
 
@@ -1302,8 +1153,6 @@ void silc_server_notify(SilcServer server,
       }
     }
 
-    silc_free(channel_id);
-
     break;
 
   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
@@ -1315,31 +1164,29 @@ void silc_server_notify(SilcServer server,
 
     /* Backup router shouldn't accept SERVER_SIGNOFF's from normal routers
        when the backup isn't acting as primary router. */
-    if (sock->type == SILC_SOCKET_TYPE_SERVER &&
+    if (idata->conn_type == SILC_CONN_SERVER &&
        server->backup_router && server->server_type == SILC_BACKUP_ROUTER)
       return;
 
     /* Get Server ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!server_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* If the ID is mine, this notify is not allowed. */
-    if (SILC_ID_SERVER_COMPARE(server_id, server->id)) {
+    if (SILC_ID_SERVER_COMPARE(SILC_ID_GET_ID(id), server->id)) {
       SILC_LOG_DEBUG(("Ignoring my own ID for SERVER_SIGNOFF"));
       break;
     }
 
     /* Get server entry */
     server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                server_id, TRUE, NULL);
+                                                SILC_ID_GET_ID(id),
+                                                TRUE, NULL);
     local = FALSE;
     if (!server_entry) {
       server_entry = silc_idlist_find_server_by_id(server->local_list,
-                                                  server_id, TRUE, NULL);
+                                                  SILC_ID_GET_ID(id),
+                                                  TRUE, NULL);
       local = TRUE;
       if (!server_entry) {
        /* If we are normal server then we might not have the server. Check
@@ -1352,27 +1199,23 @@ void silc_server_notify(SilcServer server,
 
          for (i = 1; i < silc_argument_get_arg_num(args); i++) {
            /* Get Client ID */
-           tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
-           if (!tmp)
-             continue;
-           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-           if (!client_id)
+           if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID,
+                                          &id2, NULL))
              continue;
 
            /* Get client entry */
            client = silc_idlist_find_client_by_id(server->global_list,
-                                                  client_id, TRUE, &cache);
+                                                  SILC_ID_GET_ID(id),
+                                                  TRUE, &cache);
            local = FALSE;
            if (!client) {
              client = silc_idlist_find_client_by_id(server->local_list,
-                                                    client_id, TRUE, &cache);
+                                                    SILC_ID_GET_ID(id),
+                                                    TRUE, &cache);
              local = TRUE;
-             if (!client) {
-               silc_free(client_id);
+             if (!client)
                continue;
-             }
            }
-           silc_free(client_id);
 
            /* Update statistics */
            server->stat.clients--;
@@ -1407,11 +1250,9 @@ void silc_server_notify(SilcServer server,
          }
        }
 
-       silc_free(server_id);
        goto out;
       }
     }
-    silc_free(server_id);
 
     /* For local entrys SERVER_SIGNOFF is processed only on backup router.
        It is possible that router sends server signoff for a server.  If
@@ -1419,11 +1260,8 @@ void silc_server_notify(SilcServer server,
     if (SILC_IS_LOCAL(server_entry)) {
       if (server->server_type == SILC_BACKUP_ROUTER) {
        sock = server_entry->connection;
-       SILC_LOG_DEBUG(("Closing connection %s after SERVER_SIGNOFF",
-                      sock->hostname));
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock, NULL);
-       SILC_SET_DISCONNECTING(sock);
+       SILC_LOG_DEBUG(("Closing connection after SERVER_SIGNOFF"));
+       silc_server_free_sock_user_data(server, sock, NULL);
        silc_server_close_connection(server, sock);
       }
 
@@ -1457,47 +1295,36 @@ void silc_server_notify(SilcServer server,
 
     SILC_LOG_DEBUG(("KICKED notify"));
 
-    if (!channel_id) {
-      channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                                 packet->dst_id_type);
-      if (!channel_id)
-       goto out;
-    }
+    if (!silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                       packet->dst_id_type, &channel_id,
+                       sizeof(channel_id)))
+      goto out;
 
     /* Get channel entry */
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            &channel_id, NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              &channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
-    silc_free(channel_id);
 
     /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!client_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* If the the client is not in local list we check global list */
     client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, TRUE, NULL);
+                                          SILC_ID_GET_ID(id), TRUE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list,
-                                            client_id, TRUE, NULL);
-      if (!client) {
-       silc_free(client_id);
+                                            SILC_ID_GET_ID(id), TRUE, NULL);
+      if (!client)
        goto out;
-      }
     }
-    silc_free(client_id);
 
     /* If target is founder they cannot be kicked */
     if (!silc_server_client_on_channel(client, channel, &chl))
@@ -1506,25 +1333,18 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get the kicker's Client ID */
-    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!client_id)
+    if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* If the the client is not in local list we check global list */
     client2 = silc_idlist_find_client_by_id(server->global_list,
-                                           client_id, TRUE, NULL);
+                                           SILC_ID_GET_ID(id), TRUE, NULL);
     if (!client2) {
       client2 = silc_idlist_find_client_by_id(server->local_list,
-                                             client_id, TRUE, NULL);
-      if (!client2) {
-       silc_free(client_id);
+                                             SILC_ID_GET_ID(id), TRUE, NULL);
+      if (!client2)
        goto out;
-      }
     }
-    silc_free(client_id);
 
     /* Kicker must be operator on channel */
     if (!silc_server_client_on_channel(client2, channel, &chl))
@@ -1537,8 +1357,8 @@ void silc_server_notify(SilcServer server,
 
     /* Send to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type,
-                                      FALSE, TRUE, packet->buffer->data,
-                                      packet->buffer->len, FALSE);
+                                      FALSE, TRUE, buffer->data,
+                                      silc_buffer_len(buffer));
 
     /* Remove the client from channel's invite list */
     if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
@@ -1546,7 +1366,7 @@ void silc_server_notify(SilcServer server,
       SilcArgumentPayload iargs;
       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
       ab = silc_argument_payload_encode_one(NULL, tmp, tmp_len, 3);
-      iargs = silc_argument_payload_parse(ab->data, ab->len, 1);
+      iargs = silc_argument_payload_parse(ab->data, silc_buffer_len(ab), 1);
       silc_server_inviteban_process(server, channel->invite_list, 1, iargs);
       silc_buffer_free(ab);
       silc_argument_payload_free(iargs);
@@ -1562,31 +1382,25 @@ void silc_server_notify(SilcServer server,
       /*
        * Distribute the notify to local clients on channels
        */
-      unsigned char *id, *comment;
-      SilcUInt32 id_len, comment_len;
+      unsigned char *comment;
+      SilcUInt32 comment_len;
 
       SILC_LOG_DEBUG(("KILLED notify"));
 
       /* Get client ID */
-      id = silc_argument_get_arg_type(args, 1, &id_len);
-      if (!id)
-       goto out;
-      client_id = silc_id_payload_parse_id(id, id_len, NULL);
-      if (!client_id)
+      if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
        goto out;
 
       /* If the the client is not in local list we check global list */
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, TRUE, &cache);
+                                            SILC_ID_GET_ID(id), TRUE, &cache);
       if (!client) {
        client = silc_idlist_find_client_by_id(server->local_list,
-                                              client_id, TRUE, &cache);
-       if (!client) {
-         silc_free(client_id);
+                                              SILC_ID_GET_ID(id),
+                                              TRUE, &cache);
+       if (!client)
          goto out;
-       }
       }
-      silc_free(client_id);
 
       /* If the client is one of ours, then close the connection to the
         client now. This removes the client from all channels as well. */
@@ -1603,26 +1417,21 @@ void silc_server_notify(SilcServer server,
        comment_len = 127;
 
       /* Get the killer's Client ID */
-      tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-      if (!tmp)
-       goto out;
-      client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-      if (!client_id)
+      if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
        goto out;
 
-      if (id_type == SILC_ID_CLIENT) {
+      if (id.type == SILC_ID_CLIENT) {
        /* If the the client is not in local list we check global list */
        client2 = silc_idlist_find_client_by_id(server->global_list,
-                                               client_id, TRUE, NULL);
+                                               SILC_ID_GET_ID(id),
+                                               TRUE, NULL);
        if (!client2) {
          client2 = silc_idlist_find_client_by_id(server->local_list,
-                                                 client_id, TRUE, NULL);
-         if (!client2) {
-           silc_free(client_id);
+                                                 SILC_ID_GET_ID(id),
+                                                 TRUE, NULL);
+         if (!client2)
            goto out;
-         }
        }
-       silc_free(client_id);
 
        /* Killer must be router operator */
        if (server->server_type != SILC_SERVER &&
@@ -1634,10 +1443,12 @@ void silc_server_notify(SilcServer server,
 
       /* Send the notify to local clients on the channels except to the
         client who is killed. */
+      tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+      tmp2 = silc_argument_get_arg_type(args, 3, &tmp2_len);
       silc_server_send_notify_on_channels(server, client, client,
                                          SILC_NOTIFY_TYPE_KILLED, 3,
-                                         id, id_len, comment, comment_len,
-                                         tmp, tmp_len);
+                                         tmp, tmp_len, comment, comment_len,
+                                         tmp2, tmp2_len);
 
       /* Remove the client from all channels */
       silc_server_remove_from_channels(server, NULL, client, FALSE, NULL,
@@ -1672,7 +1483,6 @@ void silc_server_notify(SilcServer server,
       client->mode = 0;
       client->router = NULL;
       client->connection = NULL;
-      cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
       break;
     }
 
@@ -1684,25 +1494,18 @@ void silc_server_notify(SilcServer server,
     SILC_LOG_DEBUG(("UMODE_CHANGE notify"));
 
     /* Get client ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!client_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get client entry */
     client = silc_idlist_find_client_by_id(server->global_list,
-                                          client_id, TRUE, NULL);
+                                          SILC_ID_GET_ID(id), TRUE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list,
-                                            client_id, TRUE, NULL);
-      if (!client) {
-       silc_free(client_id);
+                                            SILC_ID_GET_ID(id), TRUE, NULL);
+      if (!client)
        goto out;
-      }
     }
-    silc_free(client_id);
 
     /* Get the mode */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
@@ -1752,26 +1555,20 @@ void silc_server_notify(SilcServer server,
     SILC_LOG_DEBUG(("BAN notify"));
 
     /* Get Channel ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id)
+    if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
       goto out;
 
     /* Get channel entry */
     channel = silc_idlist_find_channel_by_id(server->global_list,
-                                            channel_id, NULL);
+                                            SILC_ID_GET_ID(id), NULL);
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              SILC_ID_GET_ID(id), NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
-       silc_free(channel_id);
        goto out;
       }
     }
-    silc_free(channel_id);
 
     /* Get the ban action */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
@@ -1809,8 +1606,8 @@ void silc_server_notify(SilcServer server,
       if (server->server_type == SILC_ROUTER)
        silc_server_packet_send_to_channel(server, sock, channel,
                                           packet->type, FALSE, FALSE,
-                                          packet->buffer->data,
-                                          packet->buffer->len, FALSE);
+                                          buffer->data,
+                                          silc_buffer_len(buffer));
     }
     break;
 
@@ -1829,29 +1626,28 @@ void silc_server_notify(SilcServer server,
       SILC_LOG_DEBUG(("ERROR notify (%d)", error));
 
       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
-         sock->type == SILC_SOCKET_TYPE_ROUTER) {
-       tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-       if (tmp) {
-         SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
-                         "the entry from cache"));
-         client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-         if (!client_id)
-           goto out;
-         client = silc_idlist_find_client_by_id(server->global_list,
-                                                client_id, FALSE, NULL);
-         if (client) {
-           if (client->data.public_key)
-             silc_hash_table_del_by_context(server->pk_hash,
-                                            client->data.public_key,
-                                            client);
+         idata->conn_type == SILC_CONN_ROUTER) {
+       if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+         goto out;
 
-           silc_server_remove_from_channels(server, NULL, client, TRUE,
-                                            NULL, TRUE, FALSE);
-           silc_idlist_del_data(client);
-           silc_idlist_del_client(server->global_list, client);
-         }
-         silc_free(client_id);
-       }
+       SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
+                       "the entry from cache"));
+
+       client = silc_idlist_find_client_by_id(server->global_list,
+                                              SILC_ID_GET_ID(id),
+                                              FALSE, NULL);
+       if (!client)
+         goto out;
+
+       if (client->data.public_key)
+         silc_hash_table_del_by_context(server->pk_hash,
+                                        client->data.public_key,
+                                        client);
+
+       silc_server_remove_from_channels(server, NULL, client, TRUE,
+                                        NULL, TRUE, FALSE);
+       silc_idlist_del_data(client);
+       silc_idlist_del_client(server->global_list, client);
       }
     }
     break;
@@ -1860,6 +1656,7 @@ void silc_server_notify(SilcServer server,
   case SILC_NOTIFY_TYPE_NONE:
   case SILC_NOTIFY_TYPE_MOTD:
     break;
+
   default:
     break;
   }
@@ -1868,57 +1665,52 @@ void silc_server_notify(SilcServer server,
   silc_notify_payload_free(payload);
 }
 
+void silc_server_notify(SilcServer server,
+                       SilcPacketStream sock,
+                       SilcPacket packet)
+{
+  silc_server_notify_process(server, sock, packet, &packet->buffer);
+}
+
 void silc_server_notify_list(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet)
+                            SilcPacketStream sock,
+                            SilcPacket packet)
 {
-  SilcPacketContext *new;
-  SilcBuffer buffer;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcUInt16 len;
+  SilcBuffer buffer;
 
   SILC_LOG_DEBUG(("Processing Notify List"));
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+  if (idata->conn_type == SILC_CONN_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER)
     return;
 
-  /* Make copy of the original packet context, except for the actual
-     data buffer, which we will here now fetch from the original buffer. */
-  new = silc_packet_context_alloc();
-  new->type = SILC_PACKET_NOTIFY;
-  new->flags = packet->flags;
-  new->src_id = packet->src_id;
-  new->src_id_len = packet->src_id_len;
-  new->src_id_type = packet->src_id_type;
-  new->dst_id = packet->dst_id;
-  new->dst_id_len = packet->dst_id_len;
-  new->dst_id_type = packet->dst_id_type;
-
   buffer = silc_buffer_alloc(1024);
-  new->buffer = buffer;
+  if (!buffer)
+    return;
 
-  while (packet->buffer->len) {
-    SILC_GET16_MSB(len, packet->buffer->data + 2);
-    if (len > packet->buffer->len)
+  while (silc_buffer_len(&packet->buffer)) {
+    SILC_GET16_MSB(len, packet->buffer.data + 2);
+    if (len > silc_buffer_len(&packet->buffer))
       break;
 
-    if (len > buffer->truelen) {
+    if (len > silc_buffer_truelen(buffer)) {
       silc_buffer_free(buffer);
       buffer = silc_buffer_alloc(1024 + len);
     }
 
     silc_buffer_pull_tail(buffer, len);
-    silc_buffer_put(buffer, packet->buffer->data, len);
+    silc_buffer_put(buffer, packet->buffer.data, len);
 
     /* Process the Notify */
-    silc_server_notify(server, sock, new);
+    silc_server_notify_process(server, sock, packet, buffer);
 
     silc_buffer_push_tail(buffer, len);
-    silc_buffer_pull(packet->buffer, len);
+    silc_buffer_pull(&packet->buffer, len);
   }
 
   silc_buffer_free(buffer);
-  silc_free(new);
 }
 
 /* Received private message. This resolves the destination of the message
@@ -1928,12 +1720,13 @@ void silc_server_notify_list(SilcServer server,
    the destination is not in our server (or router). */
 
 void silc_server_private_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
+                                SilcPacketStream sock,
+                                SilcPacket packet)
 {
-  SilcSocketConnection dst_sock;
+  SilcPacketStream dst_sock;
   SilcIDListData idata;
   SilcClientEntry client;
+  SilcClientID client_id;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1964,20 +1757,18 @@ void silc_server_private_message(SilcServer server,
 
     error = SILC_STATUS_ERR_NO_SUCH_CLIENT_ID;
     if (packet->src_id_type == SILC_ID_CLIENT) {
-      SilcClientID *client_id = silc_id_str2id(packet->src_id,
-                                              packet->src_id_len,
-                                              packet->src_id_type);
+      silc_id_str2id(packet->src_id, packet->src_id_len,
+                    packet->src_id_type, &client_id, sizeof(client_id));
       silc_server_send_notify_dest(server, sock, FALSE,
-                                  client_id, SILC_ID_CLIENT,
+                                  &client_id, SILC_ID_CLIENT,
                                   SILC_NOTIFY_TYPE_ERROR, 2,
                                   &error, 1,
-                                  idp->data, idp->len);
-      silc_free(client_id);
+                                  idp->data, silc_buffer_len(idp));
     } else {
       silc_server_send_notify(server, sock, FALSE,
                              SILC_NOTIFY_TYPE_ERROR, 2,
                              &error, 1,
-                             idp->data, idp->len);
+                             idp->data, silc_buffer_len(idp));
     }
 
     silc_buffer_free(idp);
@@ -1992,9 +1783,7 @@ void silc_server_private_message(SilcServer server,
   }
 
   /* Send the private message */
-  silc_server_send_private_message(server, dst_sock, idata->send_key,
-                                  idata->hmac_send, idata->psn_send++,
-                                  packet);
+  silc_server_packet_route(server, dst_sock, packet);
 }
 
 /* Received private message key packet.. This packet is never for us. It is to
@@ -2003,10 +1792,10 @@ void silc_server_private_message(SilcServer server,
    one client to another. */
 
 void silc_server_private_message_key(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    SilcPacketContext *packet)
+                                    SilcPacketStream sock,
+                                    SilcPacket packet)
 {
-  SilcSocketConnection dst_sock;
+  SilcPacketStream dst_sock;
   SilcIDListData idata;
 
   SILC_LOG_DEBUG(("Start"));
@@ -2026,8 +1815,7 @@ void silc_server_private_message_key(SilcServer server,
     return;
 
   /* Relay the packet */
-  silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, idata->psn_send++, packet, FALSE);
+  silc_server_packet_route(server, dst_sock, packet);
 }
 
 /* Processes incoming command reply packet. The command reply packet may
@@ -2035,14 +1823,12 @@ void silc_server_private_message_key(SilcServer server,
    call the command reply routine after processing the packet. */
 
 void silc_server_command_reply(SilcServer server,
-                              SilcSocketConnection sock,
-                              SilcPacketContext *packet)
+                              SilcPacketStream sock,
+                              SilcPacket packet)
 {
-  SilcBuffer buffer = packet->buffer;
+  SilcBuffer buffer = &packet->buffer;
   SilcClientEntry client = NULL;
-  SilcSocketConnection dst_sock;
-  SilcIDListData idata;
-  SilcClientID *id = NULL;
+  SilcClientID id;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -2051,13 +1837,13 @@ void silc_server_command_reply(SilcServer server,
 
   if (packet->dst_id_type == SILC_ID_CLIENT) {
     /* Destination must be one of ours */
-    id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT);
-    if (!id)
+    if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT,
+                       &id, sizeof(id)))
       return;
-    client = silc_idlist_find_client_by_id(server->local_list, id, TRUE, NULL);
+    client = silc_idlist_find_client_by_id(server->local_list, &id,
+                                          TRUE, NULL);
     if (!client) {
       SILC_LOG_ERROR(("Cannot process command reply to unknown client"));
-      silc_free(id);
       return;
     }
   }
@@ -2073,62 +1859,43 @@ void silc_server_command_reply(SilcServer server,
   /* Execute command reply locally for the command */
   silc_server_command_reply_process(server, sock, buffer);
 
-  if (packet->dst_id_type == SILC_ID_CLIENT && client && id) {
-    /* Relay the packet to the client */
-    const SilcBufferStruct p;
-
-    dst_sock = (SilcSocketConnection)client->connection;
-    idata = (SilcIDListData)client;
-
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
-                    + packet->dst_id_len + packet->padlen);
-    if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len,
-                                  idata->hmac_send, (const SilcBuffer)&p)) {
-      SILC_LOG_ERROR(("Cannot send packet"));
-      return;
-    }
-    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-
-    /* Encrypt packet */
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
-                       (SilcBuffer)&p, buffer->len);
-
-    /* Send the packet */
-    silc_server_packet_send_real(server, dst_sock, TRUE);
-
-    silc_free(id);
-  }
+  /* Relay the packet to the client */
+  if (packet->dst_id_type == SILC_ID_CLIENT && client)
+    silc_server_packet_route(server, client->connection, packet);
 }
 
 /* Process received channel message. The message can be originated from
    client or server. */
 
 void silc_server_channel_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
+                                SilcPacketStream sock,
+                                SilcPacket packet)
 {
   SilcChannelEntry channel = NULL;
-  SilcChannelID *id = NULL;
+  SilcChannelID id;
+  SilcClientID cid;
+  SilcID sid;
   void *sender_id = NULL;
   SilcClientEntry sender_entry = NULL;
+  SilcIDListData idata;
   SilcChannelClientEntry chl;
-  bool local = TRUE;
+  SilcBool local = TRUE;
 
   SILC_LOG_DEBUG(("Processing channel message"));
 
   /* Sanity checks */
   if (packet->dst_id_type != SILC_ID_CHANNEL) {
     SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
-    goto out;
+    return;
   }
 
   /* Find channel entry */
-  id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
-  if (!id)
-    goto out;
-  channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+  if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
+                     &id, sizeof(id)))
+    return;
+  channel = silc_idlist_find_channel_by_id(server->local_list, &id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+    channel = silc_idlist_find_channel_by_id(server->global_list, &id, NULL);
     if (!channel) {
       SilcBuffer idp;
       unsigned char error;
@@ -2139,47 +1906,47 @@ void silc_server_channel_message(SilcServer server,
                                        packet->dst_id_len,
                                        packet->dst_id_type);
       if (!idp)
-       goto out;
+       return;
 
       error = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
       if (packet->src_id_type == SILC_ID_CLIENT) {
-       SilcClientID *client_id = silc_id_str2id(packet->src_id,
-                                                packet->src_id_len,
-                                                packet->src_id_type);
+       silc_id_str2id(packet->src_id, packet->src_id_len,
+                      packet->src_id_type, &cid, sizeof(cid));
        silc_server_send_notify_dest(server, sock, FALSE,
-                                    client_id, SILC_ID_CLIENT,
+                                    &cid, SILC_ID_CLIENT,
                                     SILC_NOTIFY_TYPE_ERROR, 2,
-                                    &error, 1, idp->data, idp->len);
-       silc_free(client_id);
+                                    &error, 1, idp->data,
+                                    silc_buffer_len(idp));
       } else {
        silc_server_send_notify(server, sock, FALSE,
                                SILC_NOTIFY_TYPE_ERROR, 2,
-                               &error, 1, idp->data, idp->len);
+                               &error, 1, idp->data, silc_buffer_len(idp));
       }
 
       silc_buffer_free(idp);
-      goto out;
+      return;
     }
   }
 
   /* See that this client is on the channel. If the original sender is
      not client (as it can be server as well) we don't do the check. */
-  sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
-                            packet->src_id_type);
-  if (!sender_id)
-    goto out;
-  if (packet->src_id_type == SILC_ID_CLIENT) {
+  if (!silc_id_str2id2(packet->src_id, packet->src_id_len,
+                      packet->src_id_type, &sid))
+    return;
+  if (sid.type == SILC_ID_CLIENT) {
     sender_entry = silc_idlist_find_client_by_id(server->local_list,
-                                                sender_id, TRUE, NULL);
+                                                SILC_ID_GET_ID(sid),
+                                                TRUE, NULL);
     if (!sender_entry) {
       local = FALSE;
       sender_entry = silc_idlist_find_client_by_id(server->global_list,
-                                                  sender_id, TRUE, NULL);
+                                                  SILC_ID_GET_ID(sid),
+                                                  TRUE, NULL);
     }
     if (!sender_entry || !silc_server_client_on_channel(sender_entry,
                                                        channel, &chl)) {
       SILC_LOG_DEBUG(("Client not on channel"));
-      goto out;
+      return;
     }
 
     /* If channel is moderated check that client is allowed to send
@@ -2188,27 +1955,28 @@ void silc_server_channel_message(SilcServer server,
        !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Channel is silenced from normal users"));
-      goto out;
+      return;
     }
     if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
        chl->mode & SILC_CHANNEL_UMODE_CHANOP &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Channel is silenced from operators"));
-      goto out;
+      return;
     }
     if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
       SILC_LOG_DEBUG(("Sender is quieted on the channel"));
-      goto out;
+      return;
     }
 
     /* If the packet is coming from router, but the client entry is local
        entry to us then some router is rerouting this to us and it is not
        allowed. When the client is local to us it means that we've routed
        this packet to network, and now someone is routing it back to us. */
+    idata = silc_packet_get_context(sock);
     if (server->server_type == SILC_ROUTER &&
-       sock->type == SILC_SOCKET_TYPE_ROUTER && local) {
+       idata->conn_type == SILC_CONN_ROUTER && local) {
       SILC_LOG_DEBUG(("Channel message rerouted to the sender, drop it"));
-      goto out;
+      return;
     }
   }
 
@@ -2216,34 +1984,30 @@ void silc_server_channel_message(SilcServer server,
      packet for further routing as well, if needed. */
   silc_server_packet_relay_to_channel(server, sock, channel, sender_id,
                                      packet->src_id_type, sender_entry,
-                                     packet->buffer->data,
-                                     packet->buffer->len, FALSE);
-
- out:
-  silc_free(sender_id);
-  silc_free(id);
+                                     packet->buffer.data,
+                                     silc_buffer_len(&packet->buffer));
 }
 
 /* Received channel key packet. We distribute the key to all of our locally
    connected clients on the channel. */
 
 void silc_server_channel_key(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet)
+                            SilcPacketStream sock,
+                            SilcPacket packet)
 {
-  SilcBuffer buffer = packet->buffer;
+  SilcBuffer buffer = &packet->buffer;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcChannelEntry channel;
 
   if (packet->src_id_type != SILC_ID_SERVER ||
       (server->server_type == SILC_ROUTER && !server->backup_router &&
-       sock->type == SILC_SOCKET_TYPE_ROUTER))
+       idata->conn_type == SILC_CONN_ROUTER))
     return;
 
   /* Save the channel key */
   channel = silc_server_save_channel_key(server, buffer, NULL);
   if (!channel) {
-    SILC_LOG_ERROR(("Bad channel key from %s (%s)",
-                   sock->hostname, sock->ip));
+    SILC_LOG_ERROR(("Bad channel key from %s", idata->sconn->remote_host));
     return;
   }
 
@@ -2253,9 +2017,10 @@ void silc_server_channel_key(SilcServer server,
 
   if (server->server_type != SILC_BACKUP_ROUTER) {
     /* Distribute to local cell backup routers. */
-    silc_server_backup_send(server, sock->user_data,
+    silc_server_backup_send(server, (SilcServerEntry)idata,
                            SILC_PACKET_CHANNEL_KEY, 0,
-                           buffer->data, buffer->len, FALSE, TRUE);
+                           buffer->data, silc_buffer_len(buffer),
+                           FALSE, TRUE);
   }
 }
 
@@ -2263,35 +2028,36 @@ void silc_server_channel_key(SilcServer server,
    client. Client becomes registered after calling this functions. */
 
 SilcClientEntry silc_server_new_client(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet)
+                                      SilcPacketStream sock,
+                                      SilcPacket packet)
 {
-  SilcBuffer buffer = packet->buffer;
+  SilcBuffer buffer = &packet->buffer;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcClientEntry client;
   SilcClientID *client_id;
-  SilcIDListData idata;
   char *username = NULL, *realname = NULL;
   SilcUInt16 username_len;
   SilcUInt32 id_len, tmp_len;
   int ret;
-  char *hostname, *nickname, *nicknamec;
+  char *host, *nickname, *nicknamec;
+  const char *hostname, *ip;
 
   SILC_LOG_DEBUG(("Creating new client"));
 
-  if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (idata->conn_type != SILC_CONN_CLIENT)
     return NULL;
 
   /* Take client entry */
-  client = (SilcClientEntry)sock->user_data;
-  idata = (SilcIDListData)client;
+  client = (SilcClientEntry)idata;
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
 
   /* Remove the old cache entry. */
-  if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
+  if (!silc_idcache_del_by_context(server->local_list->clients, client,
+                                  NULL)) {
     SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2300,8 +2066,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_OPERATION_ALLOWED,
                                  "Too many registrations");
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2315,12 +2080,11 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_free(username);
     silc_free(realname);
     SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
-                   "connection", sock->hostname, sock->ip));
+                   "connection", hostname, ip));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2328,12 +2092,11 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_free(username);
     silc_free(realname);
     SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing "
-                   "connection", sock->hostname, sock->ip));
+                   "connection", hostname, ip));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2349,12 +2112,11 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_free(username);
     silc_free(realname);
     SILC_LOG_ERROR(("Client %s (%s) sent bad username string '%s', closing "
-                   "connection", sock->hostname, sock->ip, username));
+                   "connection", hostname, ip, username));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2367,46 +2129,39 @@ SilcClientEntry silc_server_new_client(SilcServer server,
      the client's public key. If the hostname is not present then put
      it from the resolved name or from the public key. */
   if (strchr(username, '@')) {
-    SilcPublicKeyIdentifier pident;
+    SilcSILCPublicKey silc_pubkey;
     int tlen = strcspn(username, "@");
     char *phostname = NULL;
 
-    hostname = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
+    host = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
 
-    if (strcmp(sock->hostname, sock->ip) &&
-       strcmp(sock->hostname, hostname)) {
+    if (strcmp(hostname, ip) && strcmp(hostname, host)) {
       silc_free(username);
-      silc_free(hostname);
+      silc_free(host);
       silc_free(realname);
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
-                     "connection", sock->hostname, sock->ip));
+                     "connection", hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
 
-    pident = silc_pkcs_decode_identifier(client->data.public_key->identifier);
-    if (pident) {
-      phostname = strdup(pident->host);
-      silc_pkcs_free_identifier(pident);
-    }
-
-    if (!strcmp(sock->hostname, sock->ip) &&
-       phostname && strcmp(phostname, hostname)) {
+    silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC,
+                                       client->data.public_key);
+    phostname = strdup(silc_pubkey->identifier.host);
+    if (!strcmp(hostname, ip) && phostname && strcmp(phostname, host)) {
       silc_free(username);
-      silc_free(hostname);
+      silc_free(host);
       silc_free(phostname);
       silc_free(realname);
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
-                     "connection", sock->hostname, sock->ip));
+                     "connection", hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
 
@@ -2414,38 +2169,13 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   } else {
     /* The hostname is not present, add it. */
     char *newusername;
-    /* XXX For now we cannot take the host name from the public key since
-       they are not trusted or we cannot verify them as trusted. Just take
-       what the resolved name or address is. */
-#if 0
-    if (strcmp(sock->hostname, sock->ip)) {
-#endif
-      newusername = silc_calloc(strlen(username) +
-                               strlen(sock->hostname) + 2,
-                               sizeof(*newusername));
-      strncat(newusername, username, strlen(username));
-      strncat(newusername, "@", 1);
-      strncat(newusername, sock->hostname, strlen(sock->hostname));
-      silc_free(username);
-      username = newusername;
-#if 0
-    } else {
-      SilcPublicKeyIdentifier pident =
-       silc_pkcs_decode_identifier(client->data.public_key->identifier);
-
-      if (pident) {
-       newusername = silc_calloc(strlen(username) +
-                                 strlen(pident->host) + 2,
-                                 sizeof(*newusername));
-       strncat(newusername, username, strlen(username));
-       strncat(newusername, "@", 1);
-       strncat(newusername, pident->host, strlen(pident->host));
-       silc_free(username);
-       username = newusername;
-       silc_pkcs_free_identifier(pident);
-      }
-    }
-#endif
+    newusername = silc_calloc(strlen(username) + strlen(hostname) + 2,
+                             sizeof(*newusername));
+    strncat(newusername, username, strlen(username));
+    strncat(newusername, "@", 1);
+    strncat(newusername, hostname, strlen(hostname));
+    silc_free(username);
+    username = newusername;
   }
 
   /* Create Client ID */
@@ -2454,8 +2184,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                                strlen(nicknamec), &client_id)) {
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_BAD_NICKNAME, NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2488,7 +2217,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Add the client again to the ID cache */
   silc_idcache_add(server->local_list->clients, nicknamec,
-                  client_id, client, 0, NULL);
+                  client_id, client);
 
   /* Notify our router about new client on the SILC network */
   silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
@@ -2498,8 +2227,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   /* Distribute to backup routers */
   if (server->server_type == SILC_ROUTER) {
     SilcBuffer idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
-                           idp->data, idp->len, FALSE, TRUE);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+                           idp->data, silc_buffer_len(idp), FALSE, TRUE);
     silc_buffer_free(idp);
   }
 
@@ -2526,43 +2255,44 @@ SilcClientEntry silc_server_new_client(SilcServer server,
    servers is connected to the router. */
 
 SilcServerEntry silc_server_new_server(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet)
+                                      SilcPacketStream sock,
+                                      SilcPacket packet)
 {
-  SilcBuffer buffer = packet->buffer;
+  SilcBuffer buffer = &packet->buffer;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcServerEntry new_server, server_entry;
-  SilcServerID *server_id;
-  SilcIDListData idata;
+  SilcServerID server_id;
   unsigned char *server_name, *server_namec, *id_string;
   SilcUInt16 id_len, name_len;
   int ret;
-  bool local = TRUE;
+  SilcBool local = TRUE;
+  const char *hostname, *ip;
 
   SILC_LOG_DEBUG(("Creating new server"));
 
-  if (sock->type != SILC_SOCKET_TYPE_SERVER &&
-      sock->type != SILC_SOCKET_TYPE_ROUTER)
+  if (idata->conn_type != SILC_CONN_SERVER &&
+      idata->conn_type != SILC_CONN_ROUTER)
     return NULL;
 
   /* Take server entry */
-  new_server = (SilcServerEntry)sock->user_data;
-  idata = (SilcIDListData)new_server;
+  new_server = (SilcServerEntry)idata;
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
 
   /* Statistics */
   if (server->server_type == SILC_ROUTER)
     server->stat.cell_servers++;
 
   /* Remove the old cache entry */
-  if (!silc_idcache_del_by_context(server->local_list->servers, new_server)) {
+  if (!silc_idcache_del_by_context(server->local_list->servers, new_server,
+                                  NULL)) {
     if (!silc_idcache_del_by_context(server->global_list->servers,
-                                    new_server)) {
+                                    new_server, NULL)) {
       SILC_LOG_INFO(("Unauthenticated %s attempted to register to "
-                    "network", (sock->type == SILC_SOCKET_TYPE_SERVER ?
+                    "network", (idata->conn_type == SILC_CONN_SERVER ?
                                 "server" : "router")));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
     local = FALSE;
@@ -2573,8 +2303,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_OPERATION_ALLOWED,
                                  "Too many registrations");
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2590,19 +2319,17 @@ SilcServerEntry silc_server_new_server(SilcServer server,
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
-  if (id_len > buffer->len) {
+  if (id_len > silc_buffer_len(buffer)) {
     silc_free(id_string);
     silc_free(server_name);
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2612,63 +2339,60 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   }
 
   /* Get Server ID */
-  server_id = silc_id_str2id(id_string, id_len, SILC_ID_SERVER);
-  if (!server_id) {
+  if (!silc_id_str2id(id_string, id_len, SILC_ID_SERVER, &server_id,
+                     sizeof(server_id))) {
     silc_free(id_string);
     silc_free(server_name);
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
   silc_free(id_string);
 
   /* Check for valid server ID */
-  if (!silc_id_is_valid_server_id(server, server_id, sock)) {
+  if (!silc_id_is_valid_server_id(server, &server_id, sock)) {
     SILC_LOG_INFO(("Invalid server ID sent by %s (%s)",
-                  sock->ip, sock->hostname));
+                  ip, hostname));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_BAD_SERVER_ID, NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     silc_free(server_name);
     return NULL;
   }
 
   /* Check that we do not have this ID already */
   server_entry = silc_idlist_find_server_by_id(server->local_list,
-                                              server_id, TRUE, NULL);
+                                              &server_id, TRUE, NULL);
   if (server_entry) {
     if (SILC_IS_LOCAL(server_entry)) {
       SILC_LOG_ERROR(("Too many registrations from %s (%s)",
-                     sock->ip, sock->hostname));
+                     ip, hostname));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_OPERATION_ALLOWED,
                                    "Too many registrations");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     } else {
-      silc_idcache_del_by_context(server->local_list->servers, server_entry);
+      silc_idcache_del_by_context(server->local_list->servers, server_entry,
+                                 NULL);
     }
   } else {
     server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                server_id, TRUE, NULL);
+                                                &server_id, TRUE, NULL);
     if (server_entry) {
       if (SILC_IS_LOCAL(server_entry)) {
         SILC_LOG_ERROR(("Too many registrations from %s (%s)",
-                       sock->ip, sock->hostname));
+                       ip, hostname));
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_OPERATION_ALLOWED,
                                      "Too many registrations");
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock, NULL);
+       silc_server_free_sock_user_data(server, sock, NULL);
        return NULL;
       } else {
        silc_idcache_del_by_context(server->global_list->servers,
-                                   server_entry);
+                                   server_entry, NULL);
       }
     }
   }
@@ -2678,27 +2402,26 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                       SILC_STRING_UTF8, 256, NULL);
   if (!server_namec) {
     SILC_LOG_ERROR(("Malformed server name from %s (%s)",
-                   sock->ip, sock->hostname));
+                   ip, hostname));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_OPERATION_ALLOWED,
                                  "Malfromed server name");
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
   /* Update server entry */
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
   new_server->server_name = server_name;
-  new_server->id = server_id;
+  new_server->id = silc_id_dup(&server_id, SILC_ID_SERVER);
 
   SILC_LOG_DEBUG(("New server id(%s)",
-                 silc_id_render(server_id, SILC_ID_SERVER)));
+                 silc_id_render(&server_id, SILC_ID_SERVER)));
 
   /* Add again the entry to the ID cache. */
   silc_idcache_add(local ? server->local_list->servers :
-                  server->global_list->servers, server_namec, server_id,
-                  new_server, 0, NULL);
+                  server->global_list->servers, server_namec,
+                  new_server->id, new_server);
 
   /* Distribute the information about new server in the SILC network
      to our router. If we are normal server we won't send anything
@@ -2707,13 +2430,13 @@ SilcServerEntry silc_server_new_server(SilcServer server,
       SILC_PRIMARY_ROUTE(server) != sock)
     silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
                            TRUE, new_server->id, SILC_ID_SERVER,
-                           silc_id_get_len(server_id, SILC_ID_SERVER));
+                           silc_id_get_len(&server_id, SILC_ID_SERVER));
 
   if (server->server_type == SILC_ROUTER) {
     /* Distribute to backup routers */
     SilcBuffer idp = silc_id_payload_encode(new_server->id, SILC_ID_SERVER);
-    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
-                           idp->data, idp->len, FALSE, TRUE);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0, idp->data,
+                           silc_buffer_len(idp), FALSE, TRUE);
     silc_buffer_free(idp);
   }
 
@@ -2721,8 +2444,8 @@ SilcServerEntry silc_server_new_server(SilcServer server,
      backup router. If it has been then we'll disable the server and will
      ignore everything it will send until the backup router resuming
      protocol has been completed. */
-  if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
-      silc_server_backup_replaced_get(server, server_id, NULL)) {
+  if (idata->conn_type == SILC_CONN_ROUTER &&
+      silc_server_backup_replaced_get(server, &server_id, NULL)) {
     /* Send packet to the router indicating that it cannot use this
        connection as it has been replaced by backup router. */
     SILC_LOG_DEBUG(("Remote router has been replaced by backup router, "
@@ -2735,7 +2458,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
     idata->status |= SILC_IDLIST_STATUS_DISABLED;
   } else {
     /* If it is router announce our stuff to it. */
-    if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+    if (idata->conn_type == SILC_CONN_ROUTER &&
        server->server_type == SILC_ROUTER) {
       silc_server_announce_servers(server, FALSE, 0, sock);
       silc_server_announce_clients(server, 0, sock);
@@ -2744,7 +2467,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
 
     /* Announce our information to backup router */
     if (new_server->server_type == SILC_BACKUP_ROUTER &&
-       sock->type == SILC_SOCKET_TYPE_SERVER &&
+       idata->conn_type == SILC_CONN_SERVER &&
        server->server_type == SILC_ROUTER) {
       silc_server_announce_servers(server, TRUE, 0, sock);
       silc_server_announce_clients(server, 0, sock);
@@ -2755,9 +2478,9 @@ SilcServerEntry silc_server_new_server(SilcServer server,
        to be backup router after this setting. */
     if (new_server->server_type == SILC_BACKUP_ROUTER) {
       SilcServerConfigRouter *backup;
-      backup = silc_server_config_find_backup_conn(server, sock->ip);
+      backup = silc_server_config_find_backup_conn(server, (char *)ip);
       if (!backup)
-       backup = silc_server_config_find_backup_conn(server, sock->hostname);
+       backup = silc_server_config_find_backup_conn(server, (char *)hostname);
       if (backup) {
        /* Add as our backup router */
        silc_server_backup_add(server, new_server, backup->backup_replace_ip,
@@ -2769,7 +2492,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
     /* By default the servers connected to backup router are disabled
        until backup router has become the primary */
     if (server->server_type == SILC_BACKUP_ROUTER &&
-       sock->type == SILC_SOCKET_TYPE_SERVER)
+       idata->conn_type == SILC_CONN_SERVER)
       idata->status |= SILC_IDLIST_STATUS_DISABLED;
   }
 
@@ -2780,48 +2503,48 @@ SilcServerEntry silc_server_new_server(SilcServer server,
    information about newly registered clients and servers. */
 
 static void silc_server_new_id_real(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   SilcPacketContext *packet,
-                                   int broadcast)
+                                   SilcPacketStream sock,
+                                   SilcPacket packet,
+                                   SilcBuffer buffer,
+                                   SilcBool broadcast)
 {
-  SilcBuffer buffer = packet->buffer;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcIDList id_list;
   SilcServerEntry router, server_entry;
-  SilcSocketConnection router_sock;
+  SilcPacketStream router_sock;
   SilcIDPayload idp;
   SilcIdType id_type;
-  void *id;
+  SilcServerID sender_id;
+  const char *hostname, *ip;
 
   SILC_LOG_DEBUG(("Processing new ID"));
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+  if (idata->conn_type == SILC_CONN_CLIENT ||
       server->server_type == SILC_SERVER ||
       packet->src_id_type != SILC_ID_SERVER)
     return;
 
-  idp = silc_id_payload_parse(buffer->data, buffer->len);
+  idp = silc_id_payload_parse(buffer->data, silc_buffer_len(buffer));
   if (!idp)
     return;
 
   id_type = silc_id_payload_get_type(idp);
 
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+
   /* Normal server cannot have other normal server connections */
-  server_entry = (SilcServerEntry)sock->user_data;
-  if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER &&
+  server_entry = (SilcServerEntry)idata;
+  if (id_type == SILC_ID_SERVER && idata->conn_type == SILC_CONN_SERVER &&
       server_entry->server_type == SILC_SERVER)
     goto out;
 
-  id = silc_id_payload_get_id(idp);
-  if (!id)
-    goto out;
-
   /* If the packet is coming from server then use the sender as the
      origin of the the packet. If it came from router then check the real
      sender of the packet and use that as the origin. */
-  if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+  if (idata->conn_type == SILC_CONN_SERVER) {
     id_list = server->local_list;
     router_sock = sock;
-    router = sock->user_data;
+    router = server_entry;
 
     /* If the sender is backup router and ID is server (and we are not
        backup router) then switch the entry to global list. */
@@ -2832,14 +2555,13 @@ static void silc_server_new_id_real(SilcServer server,
       router_sock = server->router ? SILC_PRIMARY_ROUTE(server) : sock;
     }
   } else {
-    void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
-                                    packet->src_id_type);
+    silc_id_str2id(packet->src_id, packet->src_id_len,
+                  packet->src_id_type, &sender_id, sizeof(sender_id));
     router = silc_idlist_find_server_by_id(server->global_list,
-                                          sender_id, TRUE, NULL);
+                                          &sender_id, TRUE, NULL);
     if (!router)
       router = silc_idlist_find_server_by_id(server->local_list,
-                                            sender_id, TRUE, NULL);
-    silc_free(sender_id);
+                                            &sender_id, TRUE, NULL);
     router_sock = sock;
     id_list = server->global_list;
   }
@@ -2851,14 +2573,18 @@ static void silc_server_new_id_real(SilcServer server,
   case SILC_ID_CLIENT:
     {
       SilcClientEntry entry;
+      SilcClientID id;
+
+      if (!silc_id_payload_get_id(idp, &id, sizeof(id)))
+       goto out;
 
       /* Check that we do not have this client already */
       entry = silc_idlist_find_client_by_id(server->global_list,
-                                           id, server->server_type,
+                                           &id, server->server_type,
                                            NULL);
       if (!entry)
        entry = silc_idlist_find_client_by_id(server->local_list,
-                                             id, server->server_type,
+                                             &id, server->server_type,
                                              NULL);
       if (entry) {
        SILC_LOG_DEBUG(("Ignoring client that we already have"));
@@ -2866,26 +2592,26 @@ static void silc_server_new_id_real(SilcServer server,
       }
 
       SILC_LOG_DEBUG(("New client id(%s) from [%s] %s",
-                     silc_id_render(id, SILC_ID_CLIENT),
-                     sock->type == SILC_SOCKET_TYPE_SERVER ?
-                     "Server" : "Router", sock->hostname));
+                     silc_id_render(&id, SILC_ID_CLIENT),
+                     idata->conn_type == SILC_CONN_SERVER ?
+                     "Server" : "Router", hostname));
 
       /* As a router we keep information of all global information in our
         global list. Cell wide information however is kept in the local
         list. */
       entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
-                                    id, router, NULL, 0);
+                                    &id, router, NULL);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
 
        /* Inform the sender that the ID is not usable */
-       silc_server_send_notify_signoff(server, sock, FALSE, id, NULL);
+       silc_server_send_notify_signoff(server, sock, FALSE, &id, NULL);
        goto out;
       }
       entry->nickname = NULL;
       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
 
-      if (sock->type == SILC_SOCKET_TYPE_SERVER)
+      if (idata->conn_type == SILC_CONN_SERVER)
        server->stat.cell_clients++;
       server->stat.clients++;
 
@@ -2905,7 +2631,8 @@ static void silc_server_new_id_real(SilcServer server,
        } else
          silc_server_send_command(server, router_sock,
                                   SILC_COMMAND_GETKEY, ++server->cmd_ident,
-                                  1, 1, buffer->data, buffer->len);
+                                  1, 1, buffer->data,
+                                  silc_buffer_len(buffer));
       }
     }
     break;
@@ -2913,26 +2640,30 @@ static void silc_server_new_id_real(SilcServer server,
   case SILC_ID_SERVER:
     {
       SilcServerEntry entry;
+      SilcServerID id;
+
+      if (!silc_id_payload_get_id(idp, &id, sizeof(id)))
+       goto out;
 
       /* If the ID is mine, ignore it. */
-      if (SILC_ID_SERVER_COMPARE(id, server->id)) {
+      if (SILC_ID_SERVER_COMPARE(&id, server->id)) {
        SILC_LOG_DEBUG(("Ignoring my own ID as new ID"));
        break;
       }
 
       /* If the ID is the sender's ID, ignore it (we have it already) */
-      if (SILC_ID_SERVER_COMPARE(id, router->id)) {
+      if (SILC_ID_SERVER_COMPARE(&id, router->id)) {
        SILC_LOG_DEBUG(("Ignoring sender's own ID"));
        break;
       }
 
       /* Check that we do not have this server already */
       entry = silc_idlist_find_server_by_id(server->global_list,
-                                           id, server->server_type,
+                                           &id, server->server_type,
                                            NULL);
       if (!entry)
        entry = silc_idlist_find_server_by_id(server->local_list,
-                                             id, server->server_type,
+                                             &id, server->server_type,
                                              NULL);
       if (entry) {
        SILC_LOG_DEBUG(("Ignoring server that we already have"));
@@ -2940,14 +2671,14 @@ static void silc_server_new_id_real(SilcServer server,
       }
 
       SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
-                     silc_id_render(id, SILC_ID_SERVER),
-                     sock->type == SILC_SOCKET_TYPE_SERVER ?
-                     "Server" : "Router", sock->hostname));
+                     silc_id_render(&id, SILC_ID_SERVER),
+                     idata->conn_type == SILC_CONN_SERVER ?
+                     "Server" : "Router", hostname));
 
       /* As a router we keep information of all global information in our
         global list. Cell wide information however is kept in the local
         list. */
-      entry = silc_idlist_add_server(id_list, NULL, 0, id, router,
+      entry = silc_idlist_add_server(id_list, NULL, 0, &id, router,
                                     router_sock);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new server to the ID Cache"));
@@ -2955,7 +2686,7 @@ static void silc_server_new_id_real(SilcServer server,
       }
       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
 
-      if (sock->type == SILC_SOCKET_TYPE_SERVER)
+      if (idata->conn_type == SILC_CONN_SERVER)
        server->stat.cell_servers++;
       server->stat.servers++;
     }
@@ -2974,16 +2705,17 @@ static void silc_server_new_id_real(SilcServer server,
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. */
   if (broadcast && server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      idata->conn_type == SILC_CONN_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            packet->type,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           buffer->data, buffer->len, FALSE);
-    silc_server_backup_send(server, sock->user_data,
+                           buffer->data, silc_buffer_len(buffer));
+    silc_server_backup_send(server, (SilcServerEntry)idata,
                            packet->type, packet->flags,
-                           packet->buffer->data, packet->buffer->len,
+                           packet->buffer.data,
+                           silc_buffer_len(&packet->buffer),
                            FALSE, TRUE);
   }
 
@@ -2995,25 +2727,25 @@ static void silc_server_new_id_real(SilcServer server,
 /* Processes incoming New ID packet. New ID Payload is used to distribute
    information about newly registered clients and servers. */
 
-void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
-                       SilcPacketContext *packet)
+void silc_server_new_id(SilcServer server, SilcPacketStream sock,
+                       SilcPacket packet)
 {
-  silc_server_new_id_real(server, sock, packet, TRUE);
+  silc_server_new_id_real(server, sock, packet, &packet->buffer, TRUE);
 }
 
 /* Receoved New Id List packet, list of New ID payloads inside one
    packet. Process the New ID payloads one by one. */
 
-void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
-                            SilcPacketContext *packet)
+void silc_server_new_id_list(SilcServer server, SilcPacketStream sock,
+                            SilcPacket packet)
 {
-  SilcPacketContext *new_id;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcBuffer idp;
   SilcUInt16 id_len;
 
   SILC_LOG_DEBUG(("Processing New ID List"));
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+  if (idata->conn_type == SILC_CONN_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER)
     return;
 
@@ -3021,53 +2753,42 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
      broadcast this packet to other routers in the network. Broadcast
      this list packet instead of multiple New ID packets. */
   if (server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      idata->conn_type == SILC_CONN_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            packet->type,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data,
-                           packet->buffer->len, FALSE);
-    silc_server_backup_send(server, sock->user_data,
+                           packet->buffer.data,
+                           silc_buffer_len(&packet->buffer));
+    silc_server_backup_send(server, (SilcServerEntry)idata,
                            packet->type, packet->flags,
-                           packet->buffer->data, packet->buffer->len,
+                           packet->buffer.data,
+                           silc_buffer_len(&packet->buffer),
                            FALSE, TRUE);
   }
 
-  /* Make copy of the original packet context, except for the actual
-     data buffer, which we will here now fetch from the original buffer. */
-  new_id = silc_packet_context_alloc();
-  new_id->type = SILC_PACKET_NEW_ID;
-  new_id->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
-  new_id->src_id = packet->src_id;
-  new_id->src_id_len = packet->src_id_len;
-  new_id->src_id_type = packet->src_id_type;
-  new_id->dst_id = packet->dst_id;
-  new_id->dst_id_len = packet->dst_id_len;
-  new_id->dst_id_type = packet->dst_id_type;
-
   idp = silc_buffer_alloc(256);
-  new_id->buffer = idp;
+  if (!idp)
+    return;
 
-  while (packet->buffer->len) {
-    SILC_GET16_MSB(id_len, packet->buffer->data + 2);
-    if ((id_len > packet->buffer->len) ||
-       (id_len > idp->truelen))
+  while (silc_buffer_len(&packet->buffer)) {
+    SILC_GET16_MSB(id_len, packet->buffer.data + 2);
+    if ((id_len > silc_buffer_len(&packet->buffer)) ||
+       (id_len > silc_buffer_truelen(idp)))
       break;
 
     silc_buffer_pull_tail(idp, 4 + id_len);
-    silc_buffer_put(idp, packet->buffer->data, 4 + id_len);
+    silc_buffer_put(idp, packet->buffer.data, 4 + id_len);
 
     /* Process the New ID */
-    silc_server_new_id_real(server, sock, new_id, FALSE);
+    silc_server_new_id_real(server, sock, packet, idp, FALSE);
 
     silc_buffer_push_tail(idp, 4 + id_len);
-    silc_buffer_pull(packet->buffer, 4 + id_len);
+    silc_buffer_pull(&packet->buffer, 4 + id_len);
   }
 
   silc_buffer_free(idp);
-  silc_free(new_id);
 }
 
 /* Received New Channel packet. Information about new channels in the
@@ -3075,34 +2796,34 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
    the new channel. This usually comes from router but also normal server
    can send this to notify channels it has when it connects to us. */
 
-void silc_server_new_channel(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet)
+static void silc_server_new_channel_process(SilcServer server,
+                                           SilcPacketStream sock,
+                                           SilcPacket packet,
+                                           SilcBuffer buffer)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcChannelPayload payload;
-  SilcChannelID *channel_id;
+  SilcChannelID channel_id;
   char *channel_name, *channel_namec = NULL;
   SilcUInt32 name_len;
-  unsigned char *id;
+  unsigned char *id, cid[32];
   SilcUInt32 id_len, cipher_len;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
   const char *cipher;
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+  if (idata->conn_type == SILC_CONN_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER ||
       server->server_type == SILC_SERVER)
     return;
 
   /* Parse the channel payload */
-  payload = silc_channel_payload_parse(packet->buffer->data,
-                                      packet->buffer->len);
+  payload = silc_channel_payload_parse(buffer->data, silc_buffer_len(buffer));
   if (!payload)
     return;
 
   /* Get the channel ID */
-  channel_id = silc_channel_get_id_parse(payload);
-  if (!channel_id) {
+  if (!silc_channel_get_id_parse(payload, &channel_id)) {
     silc_channel_payload_free(payload);
     return;
   }
@@ -3121,9 +2842,9 @@ void silc_server_new_channel(SilcServer server,
 
   id = silc_channel_get_id(payload, &id_len);
 
-  server_entry = (SilcServerEntry)sock->user_data;
+  server_entry = (SilcServerEntry)idata;
 
-  if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+  if (idata->conn_type == SILC_CONN_ROUTER) {
     /* Add the channel to global list as it is coming from router. It
        cannot be our own channel as it is coming from router. */
 
@@ -3135,15 +2856,15 @@ void silc_server_new_channel(SilcServer server,
                                                 channel_namec, NULL);
     if (!channel) {
       SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
-                     silc_id_render(channel_id, SILC_ID_CHANNEL),
-                     sock->hostname));
+                     silc_id_render(&channel_id, SILC_ID_CHANNEL),
+                     idata->sconn->remote_host));
 
       channel =
        silc_idlist_add_channel(server->global_list, strdup(channel_name),
-                               0, channel_id, sock->user_data, NULL, NULL, 0);
+                               0, silc_id_dup(&channel_id, SILC_ID_CHANNEL),
+                               (SilcServerEntry)idata, NULL, NULL, NULL);
       if (!channel) {
        silc_channel_payload_free(payload);
-       silc_free(channel_id);
        return;
       }
       channel->disabled = TRUE;    /* Disabled until someone JOINs */
@@ -3158,8 +2879,8 @@ void silc_server_new_channel(SilcServer server,
     SilcBuffer chk;
 
     SILC_LOG_DEBUG(("Channel id(%s) from [Server] %s",
-                   silc_id_render(channel_id, SILC_ID_CHANNEL),
-                   sock->hostname));
+                   silc_id_render(&channel_id, SILC_ID_CHANNEL),
+                   idata->sconn->remote_host));
 
     /* Check that we don't already have this channel */
     channel = silc_idlist_find_channel_by_name(server->local_list,
@@ -3178,14 +2899,13 @@ void silc_server_new_channel(SilcServer server,
         IP and if it is not then create a new ID and enforce the server
         to switch the ID. */
       if (server_entry->server_type != SILC_BACKUP_ROUTER &&
-         !SILC_ID_COMPARE(channel_id, server->id, server->id->ip.data_len)) {
+         !SILC_ID_COMPARE(&channel_id, server->id, server->id->ip.data_len)) {
        SilcChannelID *tmp;
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
        if (silc_id_create_channel_id(server, server->id, server->rng, &tmp)) {
          silc_server_send_notify_channel_change(server, sock, FALSE,
-                                                channel_id, tmp);
+                                                &channel_id, tmp);
          silc_channel_payload_free(payload);
-         silc_free(channel_id);
          silc_free(tmp);
        }
 
@@ -3196,10 +2916,9 @@ void silc_server_new_channel(SilcServer server,
       /* Create the channel with the provided Channel ID */
       channel = silc_server_create_new_channel_with_id(server, NULL, NULL,
                                                       channel_name,
-                                                      channel_id, FALSE);
+                                                      &channel_id, FALSE);
       if (!channel) {
        silc_channel_payload_free(payload);
-       silc_free(channel_id);
        return;
       }
       channel->disabled = TRUE;    /* Disabled until someone JOINs */
@@ -3214,18 +2933,17 @@ void silc_server_new_channel(SilcServer server,
 #endif
 
       /* Send the new channel key to the server */
-      id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-      id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
-      cipher = silc_cipher_get_name(channel->channel_key);
+      silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid),
+                    &id_len);
+      cipher = silc_cipher_get_name(channel->send_key);
       cipher_len = strlen(cipher);
-      chk = silc_channel_key_payload_encode(id_len, id,
+      chk = silc_channel_key_payload_encode(id_len, cid,
                                            cipher_len, cipher,
                                            channel->key_len / 8,
                                            channel->key);
       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
-                             chk->data, chk->len, FALSE);
+                             chk->data, silc_buffer_len(chk));
       silc_buffer_free(chk);
-      silc_free(id);
     } else {
       /* The channel exist by that name, check whether the ID's match.
         If they don't then we'll force the server to use the ID we have.
@@ -3234,14 +2952,13 @@ void silc_server_new_channel(SilcServer server,
 
       SILC_LOG_DEBUG(("Channel already exists"));
 
-      if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
+      if (!SILC_ID_CHANNEL_COMPARE(&channel_id, channel->id)) {
        /* They don't match, send CHANNEL_CHANGE notify to the server to
           force the ID change. */
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
        silc_server_send_notify_channel_change(server, sock, FALSE,
-                                              channel_id, channel->id);
+                                              &channel_id, channel->id);
        silc_channel_payload_free(payload);
-       silc_free(channel_id);
 
        /* Wait that server re-announces this channel */
        return;
@@ -3271,7 +2988,6 @@ void silc_server_new_channel(SilcServer server,
        if (silc_hash_table_count(channel->user_list)) {
          if (!silc_server_create_channel_key(server, channel, 0)) {
            silc_channel_payload_free(payload);
-           silc_free(channel_id);
            return;
          }
 
@@ -3280,22 +2996,19 @@ void silc_server_new_channel(SilcServer server,
        }
 
        /* Send to the server */
-       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
-       cipher = silc_cipher_get_name(channel->channel_key);
+       silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid),
+                      &id_len);
+       cipher = silc_cipher_get_name(channel->send_key);
        cipher_len = strlen(cipher);
-       chk = silc_channel_key_payload_encode(id_len, id,
+       chk = silc_channel_key_payload_encode(id_len, cid,
                                              cipher_len, cipher,
                                              channel->key_len / 8,
                                              channel->key);
        silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
-                               chk->data, chk->len, FALSE);
+                               chk->data, silc_buffer_len(chk));
        silc_buffer_free(chk);
-       silc_free(id);
       }
 
-      silc_free(channel_id);
-
       /* Since the channel is coming from server and we also know about it
         then send the JOIN notify to the server so that it see's our
         users on the channel "joining" the channel. */
@@ -3305,7 +3018,7 @@ void silc_server_new_channel(SilcServer server,
        silc_buffer_push(users, users->data - users->head);
        silc_server_packet_send(server, sock,
                                SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users->data, users->len, FALSE);
+                               users->data, silc_buffer_len(users));
        silc_buffer_free(users);
       }
       if (modes) {
@@ -3313,7 +3026,7 @@ void silc_server_new_channel(SilcServer server,
        silc_server_packet_send_dest(server, sock,
                                     SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                     channel->id, SILC_ID_CHANNEL,
-                                    modes->data, modes->len, FALSE);
+                                    modes->data, silc_buffer_len(modes));
        silc_buffer_free(modes);
       }
       if (users_modes) {
@@ -3322,7 +3035,7 @@ void silc_server_new_channel(SilcServer server,
                                     SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                     channel->id, SILC_ID_CHANNEL,
                                     users_modes->data,
-                                    users_modes->len, FALSE);
+                                    silc_buffer_len(users_modes));
        silc_buffer_free(users_modes);
       }
       if (channel->topic) {
@@ -3339,17 +3052,16 @@ void silc_server_new_channel(SilcServer server,
      broadcast this packet to other routers in the network. Broadcast
      this list packet instead of multiple New Channel packets. */
   if (server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      idata->conn_type == SILC_CONN_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New Channel packet"));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            packet->type,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data,
-                           packet->buffer->len, FALSE);
-    silc_server_backup_send(server, sock->user_data,
+                           buffer->data, silc_buffer_len(buffer));
+    silc_server_backup_send(server, (SilcServerEntry)idata,
                            packet->type, packet->flags,
-                           packet->buffer->data, packet->buffer->len,
+                           buffer->data, silc_buffer_len(buffer),
                            FALSE, TRUE);
   }
 
@@ -3357,62 +3069,62 @@ void silc_server_new_channel(SilcServer server,
   silc_channel_payload_free(payload);
 }
 
+/* Received New Channel packet. Information about new channels in the
+   network are distributed using this packet. Save the information about
+   the new channel. This usually comes from router but also normal server
+   can send this to notify channels it has when it connects to us. */
+
+void silc_server_new_channel(SilcServer server,
+                            SilcPacketStream sock,
+                            SilcPacket packet)
+{
+  silc_server_new_channel_process(server, sock, packet, &packet->buffer);
+}
+
 /* Received New Channel List packet, list of New Channel List payloads inside
    one packet. Process the New Channel payloads one by one. */
 
 void silc_server_new_channel_list(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketContext *packet)
+                                 SilcPacketStream sock,
+                                 SilcPacket packet)
 {
-  SilcPacketContext *new;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcBuffer buffer;
   SilcUInt16 len1, len2;
 
   SILC_LOG_DEBUG(("Processing New Channel List"));
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+  if (idata->conn_type == SILC_CONN_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER ||
       server->server_type == SILC_SERVER)
     return;
 
-  /* Make copy of the original packet context, except for the actual
-     data buffer, which we will here now fetch from the original buffer. */
-  new = silc_packet_context_alloc();
-  new->type = SILC_PACKET_NEW_CHANNEL;
-  new->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
-  new->src_id = packet->src_id;
-  new->src_id_len = packet->src_id_len;
-  new->src_id_type = packet->src_id_type;
-  new->dst_id = packet->dst_id;
-  new->dst_id_len = packet->dst_id_len;
-  new->dst_id_type = packet->dst_id_type;
-
   buffer = silc_buffer_alloc(512);
-  new->buffer = buffer;
+  if (!buffer)
+    return;
 
-  while (packet->buffer->len) {
-    SILC_GET16_MSB(len1, packet->buffer->data);
-    if ((len1 > packet->buffer->len) ||
-       (len1 > buffer->truelen))
+  while (silc_buffer_len(&packet->buffer)) {
+    SILC_GET16_MSB(len1, packet->buffer.data);
+    if ((len1 > silc_buffer_len(&packet->buffer)) ||
+       (len1 > silc_buffer_truelen(buffer)))
       break;
 
-    SILC_GET16_MSB(len2, packet->buffer->data + 2 + len1);
-    if ((len2 > packet->buffer->len) ||
-       (len2 > buffer->truelen))
+    SILC_GET16_MSB(len2, packet->buffer.data + 2 + len1);
+    if ((len2 > silc_buffer_len(&packet->buffer)) ||
+       (len2 > silc_buffer_truelen(buffer)))
       break;
 
     silc_buffer_pull_tail(buffer, 8 + len1 + len2);
-    silc_buffer_put(buffer, packet->buffer->data, 8 + len1 + len2);
+    silc_buffer_put(buffer, packet->buffer.data, 8 + len1 + len2);
 
     /* Process the New Channel */
-    silc_server_new_channel(server, sock, new);
+    silc_server_new_channel_process(server, sock, packet, buffer);
 
     silc_buffer_push_tail(buffer, 8 + len1 + len2);
-    silc_buffer_pull(packet->buffer, 8 + len1 + len2);
+    silc_buffer_pull(&packet->buffer, 8 + len1 + len2);
   }
 
   silc_buffer_free(buffer);
-  silc_free(new);
 }
 
 /* Received key agreement packet. This packet is never for us. It is to
@@ -3421,10 +3133,10 @@ void silc_server_new_channel_list(SilcServer server,
    one client to another. */
 
 void silc_server_key_agreement(SilcServer server,
-                              SilcSocketConnection sock,
-                              SilcPacketContext *packet)
+                              SilcPacketStream sock,
+                              SilcPacket packet)
 {
-  SilcSocketConnection dst_sock;
+  SilcPacketStream dst_sock;
   SilcIDListData idata;
 
   SILC_LOG_DEBUG(("Start"));
@@ -3444,9 +3156,7 @@ void silc_server_key_agreement(SilcServer server,
     return;
 
   /* Relay the packet */
-  silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, idata->psn_send++,
-                          packet, FALSE);
+  silc_server_packet_route(server, dst_sock, packet);
 }
 
 /* Received connection auth request packet that is used during connection
@@ -3458,35 +3168,38 @@ void silc_server_key_agreement(SilcServer server,
    method to use. */
 
 void silc_server_connection_auth_request(SilcServer server,
-                                        SilcSocketConnection sock,
-                                        SilcPacketContext *packet)
+                                        SilcPacketStream sock,
+                                        SilcPacket packet)
 {
   SilcServerConfigClient *client = NULL;
   SilcUInt16 conn_type;
   int ret;
   SilcAuthMethod auth_meth = SILC_AUTH_NONE;
+  const char *hostname, *ip;
 
   if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT) {
     SILC_LOG_DEBUG(("Request not from client"));
     return;
   }
 
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+
   /* Parse the payload */
-  ret = silc_buffer_unformat(packet->buffer,
+  ret = silc_buffer_unformat(&packet->buffer,
                             SILC_STR_UI_SHORT(&conn_type),
                             SILC_STR_UI_SHORT(NULL),
                             SILC_STR_END);
   if (ret == -1)
     return;
 
-  if (conn_type != SILC_SOCKET_TYPE_CLIENT)
+  if (conn_type != SILC_CONN_CLIENT)
     return;
 
   /* Get the authentication method for the client */
   auth_meth = SILC_AUTH_NONE;
-  client = silc_server_config_find_client(server, sock->ip);
+  client = silc_server_config_find_client(server, (char *)ip);
   if (!client)
-    client = silc_server_config_find_client(server, sock->hostname);
+    client = silc_server_config_find_client(server, (char *)hostname);
   if (client) {
     if (client->passphrase) {
       if (client->publickeys && !server->config->prefer_passphrase_auth)
@@ -3506,57 +3219,16 @@ void silc_server_connection_auth_request(SilcServer server,
   silc_server_send_connection_auth_request(server, sock, conn_type, auth_meth);
 }
 
-/* Received REKEY packet. The sender of the packet wants to regenerate
-   its session keys. This starts the REKEY protocol. */
-
-void silc_server_rekey(SilcServer server,
-                      SilcSocketConnection sock,
-                      SilcPacketContext *packet)
-{
-  SilcProtocol protocol;
-  SilcServerRekeyInternalContext *proto_ctx;
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
-
-  SILC_LOG_DEBUG(("Received rekey request"));
-
-  /* If we have other protocol executing we have no other choice but to
-     not execute rekey. XXX This is very bad thing.  Let's hope this
-     doesn't happen often. */
-  if (sock->protocol) {
-    SILC_LOG_WARNING(("Cannot execute REKEY protocol because other protocol "
-                     "is executing at the same time"));
-    return;
-  }
-
-  /* Allocate internal protocol context. This is sent as context
-     to the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->server = (void *)server;
-  proto_ctx->sock = silc_socket_dup(sock);
-  proto_ctx->responder = TRUE;
-  proto_ctx->pfs = idata->rekey->pfs;
-
-  /* Perform rekey protocol. Will call the final callback after the
-     protocol is over. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
-                     &protocol, proto_ctx, silc_server_rekey_final);
-  sock->protocol = protocol;
-
-  if (proto_ctx->pfs == FALSE)
-    /* Run the protocol */
-    silc_protocol_execute(protocol, server->schedule, 0, 0);
-}
-
 /* Received file transger packet. This packet is never for us. It is to
    the client in the packet's destination ID. Sending of this sort of packet
    equals sending private message, ie. it is sent point to point from
    one client to another. */
 
 void silc_server_ftp(SilcServer server,
-                    SilcSocketConnection sock,
-                    SilcPacketContext *packet)
+                    SilcPacketStream sock,
+                    SilcPacket packet)
 {
-  SilcSocketConnection dst_sock;
+  SilcPacketStream dst_sock;
   SilcIDListData idata;
 
   SILC_LOG_DEBUG(("Start"));
@@ -3576,66 +3248,64 @@ void silc_server_ftp(SilcServer server,
     return;
 
   /* Relay the packet */
-  silc_server_relay_packet(server, dst_sock, idata->send_key,
-                          idata->hmac_send, idata->psn_send++,
-                          packet, FALSE);
+  silc_server_packet_route(server, dst_sock, packet);
 }
 
 typedef struct {
   SilcServer server;
-  SilcSocketConnection sock;
-  SilcPacketContext *packet;
-  void *data;
+  SilcPacketStream sock;
+  SilcPacket packet;
+  SilcClientID client_id;
 } *SilcServerResumeResolve;
 
 SILC_SERVER_CMD_FUNC(resume_resolve)
 {
   SilcServerResumeResolve r = (SilcServerResumeResolve)context;
   SilcServer server = r->server;
-  SilcSocketConnection sock = r->sock;
+  SilcPacketStream sock = r->sock;
   SilcServerCommandReplyContext reply = context2;
   SilcClientEntry client;
+  const char *hostname, *ip;
 
   SILC_LOG_DEBUG(("Start"));
 
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+
   if (!reply || !silc_command_get_status(reply->payload, NULL, NULL)) {
     SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
-                   "closing connection", sock->hostname, sock->ip));
+                   "closing connection", hostname, ip));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  "Resuming not possible");
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_free_sock_user_data(server, sock, NULL);
     goto out;
   }
 
   if (reply && silc_command_get(reply->payload) == SILC_COMMAND_WHOIS) {
     /* Get entry to the client, and resolve it if we don't have it. */
     client = silc_idlist_find_client_by_id(server->local_list,
-                                          r->data, TRUE, NULL);
+                                          &r->client_id, TRUE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            r->data, TRUE, NULL);
+                                            &r->client_id, TRUE, NULL);
       if (!client) {
        SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
-                       "closing connection", sock->hostname, sock->ip));
+                       "closing connection", hostname, ip));
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock, NULL);
+       silc_server_free_sock_user_data(server, sock, NULL);
        goto out;
       }
     }
 
     if (!(client->mode & SILC_UMODE_DETACHED)) {
       SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
-                     "closing connection", sock->hostname, sock->ip));
+                     "closing connection", hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_server_free_sock_user_data(server, sock, NULL);
       goto out;
     }
 
@@ -3646,9 +3316,7 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
   silc_server_resume_client(server, sock, r->packet);
 
  out:
-  silc_socket_free(r->sock);
-  silc_packet_context_free(r->packet);
-  silc_free(r->data);
+  silc_packet_stream_unref(r->sock);
   silc_free(r);
 }
 
@@ -3658,60 +3326,69 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
    that the client is not detached anymore. */
 
 void silc_server_resume_client(SilcServer server,
-                              SilcSocketConnection sock,
-                              SilcPacketContext *packet)
+                              SilcPacketStream sock,
+                              SilcPacket packet)
 {
-  SilcBuffer buffer = packet->buffer, buf;
-  SilcIDListData idata;
+  SilcBuffer buffer = &packet->buffer, buf;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry detached_client;
-  SilcClientID *client_id = NULL;
+  SilcClientID client_id;
   unsigned char *id_string, *auth = NULL, *nicknamec = NULL;
+  unsigned char cid[32];
+  SilcUInt32 cid_len;
   SilcUInt16 id_len, auth_len = 0;
-  int ret;
-  bool resolved, local, nick_change = FALSE, resolve = FALSE;
+  SilcBool resolved, local, nick_change = FALSE, resolve = FALSE;
   SilcChannelEntry channel;
   SilcHashTableList htl;
   SilcChannelClientEntry chl;
   SilcServerResumeResolve r;
-  const char *cipher;
+  const char *cipher, *hostname, *ip;
 
-  ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI16_NSTRING(&id_string, &id_len),
-                            SILC_STR_END);
-  if (ret != -1)
-    client_id = silc_id_str2id(id_string, id_len, SILC_ID_CLIENT);
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
+  if (silc_buffer_unformat(buffer,
+                          SILC_STR_UI16_NSTRING(&id_string, &id_len),
+                          SILC_STR_END) < 0) {
+    if (idata->conn_type == SILC_CONN_CLIENT) {
+      SILC_LOG_ERROR(("Client %s (%s) sent incomplete resume information, "
+                     "closing connection", hostname, ip));
+      silc_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                   "Resuming not possible");
+      silc_server_free_sock_user_data(server, sock, NULL);
+    }
+    goto out;
+  }
+
+  silc_id_str2id(id_string, id_len, SILC_ID_CLIENT, &client_id,
+                sizeof(client_id));
+
+  if (idata->conn_type == SILC_CONN_CLIENT) {
     /* Client send this and is attempting to resume to old client session */
     SilcClientEntry client;
     SilcBuffer keyp;
 
-    if (ret != -1) {
-      silc_buffer_pull(buffer, 2 + id_len);
-      auth = buffer->data;
-      auth_len = buffer->len;
-      silc_buffer_push(buffer, 2 + id_len);
-    }
+    silc_buffer_pull(buffer, 2 + id_len);
+    auth = buffer->data;
+    auth_len = silc_buffer_len(buffer);
+    silc_buffer_push(buffer, 2 + id_len);
 
-    if (!client_id || auth_len < 128) {
+    if (auth_len < 128) {
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete resume information, "
-                     "closing connection", sock->hostname, sock->ip));
+                     "closing connection", hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      silc_free(client_id);
-      return;
+      silc_server_free_sock_user_data(server, sock, NULL);
+      goto out;
     }
 
     /* Take client entry of this connection */
-    client = (SilcClientEntry)sock->user_data;
-    idata = (SilcIDListData)client;
+    client = (SilcClientEntry)idata;
 
     /* Get entry to the client, and resolve it if we don't have it. */
-    detached_client = silc_server_query_client(server, client_id, FALSE,
+    detached_client = silc_server_query_client(server, &client_id, FALSE,
                                               &resolved);
     if (!detached_client) {
       if (resolved) {
@@ -3720,52 +3397,46 @@ void silc_server_resume_client(SilcServer server,
        SILC_LOG_DEBUG(("Resolving client"));
        r = silc_calloc(1, sizeof(*r));
        if (!r)
-         return;
+         goto out;
+       silc_packet_stream_ref(sock);
        r->server = server;
-       r->sock = silc_socket_dup(sock);
-       r->packet = silc_packet_context_dup(packet);
-       r->data = client_id;
+       r->sock = sock;
+       r->packet = packet;
+       r->client_id = client_id;
        silc_server_command_pending(server, SILC_COMMAND_WHOIS,
                                    server->cmd_ident,
                                    silc_server_command_resume_resolve, r);
+       return;
       } else {
        SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
-                       "closing connection", sock->hostname, sock->ip));
+                       "closing connection", hostname, ip));
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock, NULL);
-       silc_free(client_id);
+       silc_server_free_sock_user_data(server, sock, NULL);
+       goto out;
       }
-      return;
     }
 
     if (detached_client->data.status & SILC_IDLIST_STATUS_RESUMED) {
       SILC_LOG_ERROR(("Client %s (%s) tried to attach more than once, "
-                     "closing connection", sock->hostname, sock->ip));
+                     "closing connection", hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                     SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      silc_free(client_id);
-
-      return;
+      silc_server_free_sock_user_data(server, sock, NULL);
+      goto out;
     }
 
     if (detached_client->resuming_client &&
        detached_client->resuming_client != client) {
       SILC_LOG_ERROR(("Client %s (%s) tried to attach more than once, "
-                     "closing connection", sock->hostname, sock->ip));
+                     "closing connection", hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                     SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      silc_free(client_id);
-
-      return;
+      silc_server_free_sock_user_data(server, sock, NULL);
+      goto out;
     }
 
     if (!detached_client->resuming_client)
@@ -3786,14 +3457,15 @@ void silc_server_resume_client(SilcServer server,
        /* The client info is being resolved. Reprocess this packet after
           receiving the reply to the query. */
        SILC_LOG_DEBUG(("Resolving client info"));
-       silc_server_query_client(server, client_id, TRUE, NULL);
+       silc_server_query_client(server, &client_id, TRUE, NULL);
        r = silc_calloc(1, sizeof(*r));
        if (!r)
          return;
+       silc_packet_stream_ref(sock);
        r->server = server;
-       r->sock = silc_socket_dup(sock);
-       r->packet = silc_packet_context_dup(packet);
-       r->data = client_id;
+       r->sock = sock;
+       r->packet = packet;
+       r->client_id = client_id;
        silc_server_command_pending(server, SILC_COMMAND_WHOIS,
                                    server->cmd_ident,
                                    silc_server_command_resume_resolve, r);
@@ -3801,14 +3473,12 @@ void silc_server_resume_client(SilcServer server,
       }
       if (server->server_type == SILC_SERVER) {
        SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
-                       "closing connection", sock->hostname, sock->ip));
+                       "closing connection", hostname, ip));
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock, NULL);
-       silc_free(client_id);
-       return;
+       silc_server_free_sock_user_data(server, sock, NULL);
+       goto out;
       }
     }
 
@@ -3821,40 +3491,38 @@ void silc_server_resume_client(SilcServer server,
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock, NULL);
-       silc_free(client_id);
+       silc_server_free_sock_user_data(server, sock, NULL);
+       goto out;
       } else {
        /* We must retrieve the detached client's public key by sending
           GETKEY command. Reprocess this packet after receiving the key */
-       SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
-       SilcSocketConnection dest_sock =
-         silc_server_get_client_route(server, NULL, 0, client_id, NULL, NULL);
+       SilcBuffer idp = silc_id_payload_encode(&client_id, SILC_ID_CLIENT);
+       SilcPacketStream dest_sock =
+         silc_server_get_client_route(server, NULL, 0, &client_id,
+                                      NULL, NULL);
 
        SILC_LOG_DEBUG(("Resolving client public key"));
 
        silc_server_send_command(server, dest_sock ? dest_sock :
                                 SILC_PRIMARY_ROUTE(server),
                                 SILC_COMMAND_GETKEY, ++server->cmd_ident,
-                                1, 1, idp->data, idp->len);
+                                1, 1, idp->data, silc_buffer_len(idp));
 
        r = silc_calloc(1, sizeof(*r));
-       if (!r) {
-         silc_free(client_id);
+       if (!r)
          return;
-       }
-
+       silc_packet_stream_ref(sock);
        r->server = server;
-       r->sock = silc_socket_dup(sock);
-       r->packet = silc_packet_context_dup(packet);
+       r->sock = sock;
+       r->packet = packet;
+       r->client_id = client_id;
        silc_server_command_pending(server, SILC_COMMAND_GETKEY,
                                    server->cmd_ident,
                                    silc_server_command_resume_resolve, r);
 
        silc_buffer_free(idp);
+       return;
       }
-      silc_free(client_id);
-      return;
     } else if (!silc_pkcs_public_key_compare(detached_client->data.public_key,
                                             idata->public_key)) {
       /* We require that the connection and resuming authentication data
@@ -3864,10 +3532,8 @@ void silc_server_resume_client(SilcServer server,
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      silc_free(client_id);
-      return;
+      silc_server_free_sock_user_data(server, sock, NULL);
+      goto out;
     }
 
     /* Verify the authentication payload.  This has to be successful in
@@ -3878,14 +3544,12 @@ void silc_server_resume_client(SilcServer server,
                               idata->hash, detached_client->id,
                               SILC_ID_CLIENT)) {
       SILC_LOG_ERROR(("Client %s (%s) resume authentication failed, "
-                     "closing connection", sock->hostname, sock->ip));
+                     "closing connection", hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      silc_free(client_id);
-      return;
+      silc_server_free_sock_user_data(server, sock, NULL);
+      goto out;
     }
 
     /* Check nickname */
@@ -3896,32 +3560,32 @@ void silc_server_resume_client(SilcServer server,
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_NICKNAME,
                                    "Malformed nickname, cannot resume");
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      return;
+      silc_server_free_sock_user_data(server, sock, NULL);
+      goto out;
     }
 
     /* If the ID is not based in our ID then change it */
     if (!SILC_ID_COMPARE(detached_client->id, server->id,
                         server->id->ip.data_len)) {
-      silc_free(client_id);
+      SilcClientID *new_id;
       if (!silc_id_create_client_id(server, server->id, server->rng,
                                    server->md5hash, nicknamec,
-                                   strlen(nicknamec), &client_id)) {
+                                   strlen(nicknamec), &new_id)) {
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_BAD_NICKNAME,
                                      "Resuming not possible");
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock, NULL);
-       return;
+       silc_server_free_sock_user_data(server, sock, NULL);
+       goto out;
       }
       nick_change = TRUE;
+      client_id = *new_id;
+      silc_free(new_id);
     }
 
     /* Now resume the client to the network */
 
     silc_schedule_task_del_by_context(server->schedule, detached_client);
-    sock->user_data = detached_client;
+    silc_packet_set_context(sock, detached_client);
     detached_client->connection = sock;
 
     if (detached_client->data.public_key)
@@ -3980,10 +3644,10 @@ void silc_server_resume_client(SilcServer server,
     /* Send to primary router */
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_RESUME_CLIENT, 0,
-                           buf->data, buf->len, TRUE);
+                           buf->data, silc_buffer_len(buf));
     silc_server_backup_send(server, client->router,
                            SILC_PACKET_RESUME_CLIENT, 0,
-                           buf->data, buf->len, TRUE, TRUE);
+                           buf->data, silc_buffer_len(buf), TRUE, TRUE);
 
     /* As router we must deliver this packet directly to the original
        server whom this client was earlier. */
@@ -3991,7 +3655,7 @@ void silc_server_resume_client(SilcServer server,
        client->router->server_type != SILC_ROUTER)
       silc_server_packet_send(server, client->router->connection,
                              SILC_PACKET_RESUME_CLIENT, 0,
-                             buf->data, buf->len, TRUE);
+                             buf->data, silc_buffer_len(buf));
     silc_buffer_free(buf);
     client->router = NULL;
 
@@ -3999,7 +3663,7 @@ void silc_server_resume_client(SilcServer server,
       /* Notify about Client ID change, nickname doesn't actually change. */
       silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
                                          SILC_BROADCAST(server),
-                                         client->id, client_id,
+                                         client->id, &client_id,
                                          client->nickname);
     }
 
@@ -4023,18 +3687,18 @@ void silc_server_resume_client(SilcServer server,
 
     /* Send the new client ID to the client. After this client may start
        receiving other packets, and may start sending packets too. */
-    silc_server_send_new_id(server, sock, FALSE, client_id, SILC_ID_CLIENT,
-                           silc_id_get_len(client_id, SILC_ID_CLIENT));
+    silc_server_send_new_id(server, sock, FALSE, &client_id, SILC_ID_CLIENT,
+                           silc_id_get_len(&client_id, SILC_ID_CLIENT));
 
     if (nick_change) {
       /* Send NICK change notify to channels as well. */
       SilcBuffer oidp, nidp;
       oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-      nidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+      nidp = silc_id_payload_encode(&client_id, SILC_ID_CLIENT);
       silc_server_send_notify_on_channels(server, NULL, client,
                                          SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
-                                         oidp->data, oidp->len,
-                                         nidp->data, nidp->len,
+                                         oidp->data, silc_buffer_len(oidp),
+                                         nidp->data, silc_buffer_len(nidp),
                                          client->nickname,
                                          strlen(client->nickname));
       silc_buffer_free(oidp);
@@ -4042,13 +3706,13 @@ void silc_server_resume_client(SilcServer server,
     }
 
     /* Add the client again to the ID cache to get it to correct list */
-    if (!silc_idcache_del_by_context(server->local_list->clients, client))
-      silc_idcache_del_by_context(server->global_list->clients, client);
+    if (!silc_idcache_del_by_context(server->local_list->clients, client,
+                                    NULL))
+      silc_idcache_del_by_context(server->global_list->clients, client, NULL);
     silc_free(client->id);
-    client->id = client_id;
-    client_id = NULL;
+    *client->id = client_id;
     silc_idcache_add(server->local_list->clients, nicknamec,
-                    client->id, client, 0, NULL);
+                    client->id, client);
 
     /* Send some nice info to the client */
     silc_server_send_connect_notifys(server, sock, client);
@@ -4056,32 +3720,30 @@ void silc_server_resume_client(SilcServer server,
     /* Send all channel keys of channels the client has joined */
     silc_hash_table_list(client->channels, &htl);
     while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
-      bool created = FALSE;
+      SilcBool created = FALSE;
       channel = chl->channel;
 
       if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
        continue;
 
       /* If we don't have channel key, then create one */
-      if (!channel->channel_key) {
+      if (!channel->send_key) {
        if (!silc_server_create_channel_key(server, channel, 0))
          continue;
        created = TRUE;
       }
 
-      id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-      cipher = silc_cipher_get_name(channel->channel_key);
+      silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid),
+                    &cid_len);
+      cipher = silc_cipher_get_name(channel->send_key);
       keyp =
-       silc_channel_key_payload_encode(silc_id_get_len(channel->id,
-                                                       SILC_ID_CHANNEL),
-                                       id_string,
+       silc_channel_key_payload_encode(cid_len, cid,
                                        strlen(cipher), cipher,
                                        channel->key_len / 8, channel->key);
-      silc_free(id_string);
 
       /* Send the channel key to the client */
       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
-                             keyp->data, keyp->len, FALSE);
+                             keyp->data, silc_buffer_len(keyp));
 
       /* Distribute the channel key to channel */
       if (created) {
@@ -4089,36 +3751,31 @@ void silc_server_resume_client(SilcServer server,
                                     server->server_type == SILC_ROUTER ?
                                     FALSE : !server->standalone);
        silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
-                               keyp->data, keyp->len, FALSE, TRUE);
+                               keyp->data, silc_buffer_len(keyp),
+                               FALSE, TRUE);
       }
 
       silc_buffer_free(keyp);
     }
     silc_hash_table_list_reset(&htl);
 
-  } else if (sock->type != SILC_SOCKET_TYPE_CLIENT) {
+  } else if (idata->conn_type != SILC_CONN_CLIENT) {
     /* Server or router sent this to us to notify that that a client has
        been resumed. */
     SilcServerEntry server_entry;
-    SilcServerID *server_id;
-
-    if (!client_id) {
-      SILC_LOG_DEBUG(("Malformed resuming packet"));
-      return;
-    }
+    SilcServerID server_id;
 
     /* Get entry to the client, and resolve it if we don't have it. */
     detached_client = silc_idlist_find_client_by_id(server->local_list,
-                                                   client_id, TRUE,
+                                                   &client_id, TRUE,
                                                    &id_cache);
     if (!detached_client) {
       detached_client = silc_idlist_find_client_by_id(server->global_list,
-                                                     client_id, TRUE,
+                                                     &client_id, TRUE,
                                                      &id_cache);
       if (!detached_client) {
        SILC_LOG_DEBUG(("Resuming client is unknown"));
-       silc_free(client_id);
-       return;
+       goto out;
       }
     }
 
@@ -4133,15 +3790,13 @@ void silc_server_resume_client(SilcServer server,
       SILC_LOG_DEBUG(("Attempting to re-resume client, killing both"));
       silc_server_kill_client(server, detached_client, NULL,
                              server->id, SILC_ID_SERVER);
-      silc_free(client_id);
-      return;
+      goto out;
     }
 
     /* Check whether client is detached at all */
     if (!(detached_client->mode & SILC_UMODE_DETACHED)) {
       SILC_LOG_DEBUG(("Client is not detached"));
-      silc_free(client_id);
-      return;
+      goto out;
     }
 
     /* Check nickname */
@@ -4149,10 +3804,8 @@ void silc_server_resume_client(SilcServer server,
       nicknamec = silc_identifier_check(detached_client->nickname,
                                        strlen(detached_client->nickname),
                                        SILC_STRING_UTF8, 128, NULL);
-      if (!nicknamec) {
-       silc_free(client_id);
-       return;
-      }
+      if (!nicknamec)
+       goto out;
     }
 
     SILC_LOG_DEBUG(("Resuming detached client"));
@@ -4160,16 +3813,17 @@ void silc_server_resume_client(SilcServer server,
     /* If the sender of this packet is server and we are router we need to
        broadcast this packet to other routers in the network. */
     if (server->server_type == SILC_ROUTER &&
-       sock->type == SILC_SOCKET_TYPE_SERVER &&
+       idata->conn_type == SILC_CONN_SERVER &&
        !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
       SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              packet->type,
                              packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                             buffer->data, buffer->len, FALSE);
-      silc_server_backup_send(server, sock->user_data,
+                             buffer->data, silc_buffer_len(buffer));
+      silc_server_backup_send(server, (SilcServerEntry)idata,
                              packet->type, packet->flags,
-                             packet->buffer->data, packet->buffer->len,
+                             packet->buffer.data,
+                             silc_buffer_len(&packet->buffer),
                              FALSE, TRUE);
     }
 
@@ -4185,7 +3839,6 @@ void silc_server_resume_client(SilcServer server,
     detached_client->mode &= ~SILC_UMODE_DETACHED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
     detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
-    id_cache->expire = 0;
 
     /* Check if anyone is watching this client */
     if (server->server_type == SILC_ROUTER)
@@ -4195,42 +3848,36 @@ void silc_server_resume_client(SilcServer server,
     silc_schedule_task_del_by_context(server->schedule, detached_client);
 
     /* Get the new owner of the resumed client */
-    server_id = silc_id_str2id(packet->src_id, packet->src_id_len,
-                              packet->src_id_type);
-    if (!server_id) {
-      silc_free(client_id);
-      return;
-    }
+    if (!silc_id_str2id(packet->src_id, packet->src_id_len,
+                       packet->src_id_type, &server_id, sizeof(server_id)))
+      goto out;
 
     /* Get server entry */
     server_entry = silc_idlist_find_server_by_id(server->global_list,
-                                                server_id, TRUE, NULL);
+                                                &server_id, TRUE, NULL);
     local = FALSE;
     if (!server_entry) {
       server_entry = silc_idlist_find_server_by_id(server->local_list,
-                                                  server_id, TRUE, NULL);
+                                                  &server_id, TRUE, NULL);
       local = TRUE;
-      if (!server_entry) {
-       silc_free(server_id);
-       silc_free(client_id);
-       return;
-      }
+      if (!server_entry)
+       goto out;
     }
 
     if (server->server_type == SILC_ROUTER &&
-       sock->type == SILC_SOCKET_TYPE_ROUTER &&
+       idata->conn_type == SILC_CONN_ROUTER &&
        server_entry->server_type == SILC_ROUTER)
       local = FALSE;
 
     /* Change the client to correct list. */
     if (!silc_idcache_del_by_context(server->local_list->clients,
-                                    detached_client))
+                                    detached_client, NULL))
       silc_idcache_del_by_context(server->global_list->clients,
-                                 detached_client);
+                                 detached_client, NULL);
     silc_idcache_add(local && server->server_type == SILC_ROUTER ?
                     server->local_list->clients :
                     server->global_list->clients, nicknamec,
-                    detached_client->id, detached_client, FALSE, NULL);
+                    detached_client->id, detached_client);
 
     /* Change the owner of the client */
     detached_client->router = server_entry;
@@ -4243,9 +3890,8 @@ void silc_server_resume_client(SilcServer server,
          silc_server_channel_has_global(chl->channel);
       silc_hash_table_list_reset(&htl);
     }
-
-    silc_free(server_id);
   }
 
-  silc_free(client_id);
+ out:
+  silc_packet_free(packet);
 }
index b28d3de498a0197bc4d14a2258d688fbd6e625d4..873ba7ca6194b0d6ecd5403e429463fa793b024a 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
-  
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 /* Prototypes */
 
 void silc_server_notify(SilcServer server,
-                       SilcSocketConnection sock,
-                       SilcPacketContext *packet);
+                       SilcPacketStream sock,
+                       SilcPacket packet);
 void silc_server_notify_list(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet);
+                            SilcPacketStream sock,
+                            SilcPacket packet);
 void silc_server_private_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet);
+                                SilcPacketStream sock,
+                                SilcPacket packet);
 void silc_server_private_message_key(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    SilcPacketContext *packet);
+                                    SilcPacketStream sock,
+                                    SilcPacket packet);
 void silc_server_command_reply(SilcServer server,
-                              SilcSocketConnection sock,
-                              SilcPacketContext *packet);
+                              SilcPacketStream sock,
+                              SilcPacket packet);
 void silc_server_channel_message(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet);
+                                SilcPacketStream sock,
+                                SilcPacket packet);
 void silc_server_channel_key(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet);
+                            SilcPacketStream sock,
+                            SilcPacket packet);
 SilcClientEntry silc_server_new_client(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet);
+                                      SilcPacketStream sock,
+                                      SilcPacket packet);
 SilcServerEntry silc_server_new_server(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      SilcPacketContext *packet);
+                                      SilcPacketStream sock,
+                                      SilcPacket packet);
 void silc_server_new_channel(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet);
+                            SilcPacketStream sock,
+                            SilcPacket packet);
 void silc_server_new_channel_list(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketContext *packet);
-void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
-                       SilcPacketContext *packet);
-void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
-                            SilcPacketContext *packet);
+                                 SilcPacketStream sock,
+                                 SilcPacket packet);
+void silc_server_new_id(SilcServer server, SilcPacketStream sock,
+                       SilcPacket packet);
+void silc_server_new_id_list(SilcServer server, SilcPacketStream sock,
+                            SilcPacket packet);
 void silc_server_remove_id(SilcServer server,
-                          SilcSocketConnection sock,
-                          SilcPacketContext *packet);
+                          SilcPacketStream sock,
+                          SilcPacket packet);
 void silc_server_remove_id_list(SilcServer server,
-                               SilcSocketConnection sock,
-                               SilcPacketContext *packet);
+                               SilcPacketStream sock,
+                               SilcPacket packet);
 void silc_server_key_agreement(SilcServer server,
-                              SilcSocketConnection sock,
-                              SilcPacketContext *packet);
+                              SilcPacketStream sock,
+                              SilcPacket packet);
 void silc_server_connection_auth_request(SilcServer server,
-                                        SilcSocketConnection sock,
-                                        SilcPacketContext *packet);
-void silc_server_rekey(SilcServer server,
-                      SilcSocketConnection sock,
-                      SilcPacketContext *packet);
+                                        SilcPacketStream sock,
+                                        SilcPacket packet);
 void silc_server_ftp(SilcServer server,
-                    SilcSocketConnection sock,
-                    SilcPacketContext *packet);
+                    SilcPacketStream sock,
+                    SilcPacket packet);
 void silc_server_resume_client(SilcServer server,
-                              SilcSocketConnection sock,
-                              SilcPacketContext *packet);
+                              SilcPacketStream sock,
+                              SilcPacket packet);
 
 #endif
index 42a936e05c04606b707221e3b42726d43dfc1881..7e19280e1649376bb4ab38c8a7afe5431d86b470 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   GNU General Public License for more details.
 
 */
-/*
- * Server packet routines to send packets.
- */
-/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
 
-/* Routine that sends packet or marks packet to be sent. This is used
-   directly only in special cases. Normal cases should use
-   silc_server_packet_send. Returns < 0 error. */
-
-int silc_server_packet_send_real(SilcServer server,
-                                SilcSocketConnection sock,
-                                bool force_send)
-{
-  int ret;
-
-  /* If disconnecting, ignore the data */
-  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
-    return -1;
-
-  /* Send the packet */
-  ret = silc_packet_send(sock, FALSE);
-  if (ret != -2) {
-    if (ret == -1) {
-      SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
-      SILC_UNSET_OUTBUF_PENDING(sock);
-      silc_buffer_clear(sock->outbuf);
-
-      SILC_LOG_ERROR(("Error sending packet to 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")));
-
-      if (sock->user_data) {
-       /* If backup then mark that resuming will not be allowed */
-       if (server->server_type == SILC_ROUTER && !server->backup_router &&
-           sock->type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerEntry server_entry = sock->user_data;
-         if (server_entry->server_type == SILC_BACKUP_ROUTER)
-           server->backup_closed = TRUE;
-       }
-
-       silc_server_free_sock_user_data(server, sock, NULL);
-      }
-      SILC_SET_DISCONNECTING(sock);
-      silc_server_close_connection(server, sock);
-      return ret;
-    }
-
-    server->stat.packets_sent++;
-    return ret;
-  }
-
-  /* Mark that there is some outgoing data available for this connection.
-     This call sets the connection both for input and output (the input
-     is set always and this call keeps the input setting, actually).
-     Actual data sending is performed by silc_server_packet_process. */
-  SILC_SET_CONNECTION_FOR_OUTPUT(server->schedule, sock->sock);
-
-  /* Mark to socket that data is pending in outgoing buffer. This flag
-     is needed if new data is added to the buffer before the earlier
-     put data is sent to the network. */
-  SILC_SET_OUTBUF_PENDING(sock);
+/* Send packet to remote connection */
 
-  return 0;
-}
-
-/* Assembles a new packet to be sent out to network. This doesn't actually
-   send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If
-   argument force_send is TRUE the packet is sent immediately and not put
-   to queue. Normal case is that the packet is not sent immediately. */
-
-void silc_server_packet_send(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketType type,
-                            SilcPacketFlags flags,
-                            unsigned char *data,
-                            SilcUInt32 data_len,
-                            bool force_send)
+SilcBool silc_server_packet_send(SilcServer server,
+                                SilcPacketStream sock,
+                                SilcPacketType type,
+                                SilcPacketFlags flags,
+                                unsigned char *data,
+                                SilcUInt32 data_len)
 {
-  void *dst_id = NULL;
-  SilcIdType dst_id_type = SILC_ID_NONE;
   SilcIDListData idata;
 
   if (!sock)
-    return;
+    return FALSE;
 
-  idata = (SilcIDListData)sock->user_data;
+  idata = silc_packet_get_context(sock);
 
-  /* If disconnecting, ignore the data */
-  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
-    return;
-
-  /* If entry is disabled do not sent anything.  Allow hearbeat and
-     rekeys, though */
+  /* If entry is disabled do not sent anything.  Allow hearbeat though */
   if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
-       type != SILC_PACKET_HEARTBEAT && type != SILC_PACKET_REKEY &&
-       type != SILC_PACKET_REKEY_DONE && type != SILC_PACKET_KEY_EXCHANGE_1
-       && type != SILC_PACKET_KEY_EXCHANGE_2) ||
-      (sock->user_data == server->id_entry)) {
+       type != SILC_PACKET_HEARTBEAT) ||
+      ((SilcServerEntry)idata == server->id_entry)) {
     SILC_LOG_DEBUG(("Connection is disabled"));
-    return;
+    return FALSE;
   }
 
-  /* Get data used in the packet sending, keys and stuff */
-  switch(sock->type) {
-  case SILC_SOCKET_TYPE_CLIENT:
-    if (sock->user_data) {
-      dst_id = ((SilcClientEntry)sock->user_data)->id;
-      dst_id_type = SILC_ID_CLIENT;
-    }
-    break;
-  case SILC_SOCKET_TYPE_SERVER:
-  case SILC_SOCKET_TYPE_ROUTER:
-    if (sock->user_data) {
-      dst_id = ((SilcServerEntry)sock->user_data)->id;
-      dst_id_type = SILC_ID_SERVER;
-    }
-    break;
-  default:
-    break;
-  }
+  SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
 
-  silc_server_packet_send_dest(server, sock, type, flags, dst_id,
-                              dst_id_type, data, data_len, force_send);
+  return silc_packet_send(sock, type, flags, (const unsigned char *)data,
+                         data_len);
 }
 
-/* Assembles a new packet to be sent out to network. This doesn't actually
-   send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If
-   argument force_send is TRUE the packet is sent immediately and not put
-   to queue. Normal case is that the packet is not sent immediately.
-   Destination information is sent as argument for this function. */
-
-void silc_server_packet_send_dest(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketType type,
-                                 SilcPacketFlags flags,
-                                 void *dst_id,
-                                 SilcIdType dst_id_type,
-                                 unsigned char *data,
-                                 SilcUInt32 data_len,
-                                 bool force_send)
+/* Send packet to remote connection with specific destination ID. */
+
+SilcBool silc_server_packet_send_dest(SilcServer server,
+                                     SilcPacketStream sock,
+                                     SilcPacketType type,
+                                     SilcPacketFlags flags,
+                                     void *dst_id,
+                                     SilcIdType dst_id_type,
+                                     unsigned char *data,
+                                     SilcUInt32 data_len)
 {
-  SilcPacketContext packetdata;
-  const SilcBufferStruct packet;
   SilcIDListData idata;
-  SilcCipher cipher = NULL;
-  SilcHmac hmac = NULL;
-  SilcUInt32 sequence = 0;
-  unsigned char *dst_id_data = NULL;
-  SilcUInt32 dst_id_len = 0;
-  int block_len = 0;
-
-  /* If disconnecting, ignore the data */
-  if (!sock || SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
-    return;
 
-  idata = (SilcIDListData)sock->user_data;
+  if (!sock)
+    return FALSE;
+
+  idata = silc_packet_get_context(sock);
 
-  /* If entry is disabled do not sent anything.  Allow hearbeat and
-     rekeys, though */
+  /* If entry is disabled do not sent anything.  Allow hearbeat though */
   if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
-       type != SILC_PACKET_HEARTBEAT && type != SILC_PACKET_REKEY &&
-       type != SILC_PACKET_REKEY_DONE && type != SILC_PACKET_KEY_EXCHANGE_1
-       && type != SILC_PACKET_KEY_EXCHANGE_2) ||
-      (sock->user_data == server->id_entry)) {
+       type != SILC_PACKET_HEARTBEAT) ||
+      ((SilcServerEntry)idata == server->id_entry)) {
     SILC_LOG_DEBUG(("Connection is disabled"));
-    return;
+    return FALSE;
   }
 
-  SILC_LOG_DEBUG(("Sending %s packet (forced=%s)",
-                 silc_get_packet_name(type), force_send ? "yes" : "no"));
-
-  if (dst_id) {
-    dst_id_data = silc_id_id2str(dst_id, dst_id_type);
-    dst_id_len = silc_id_get_len(dst_id, dst_id_type);
-  }
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
-    sequence = idata->psn_send++;
-    if (cipher)
-      block_len = silc_cipher_get_block_len(cipher);
-
-    /* Check for mandatory rekey */
-    if (sequence == SILC_SERVER_REKEY_THRESHOLD)
-      silc_schedule_task_add(server->schedule, sock->sock,
-                            silc_server_rekey_callback, sock, 0, 1,
-                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-  }
-
-  /* Set the packet context pointers */
-  packetdata.type = type;
-  packetdata.flags = flags;
-  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
-  packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
-  packetdata.src_id_type = SILC_ID_SERVER;
-  packetdata.dst_id = dst_id_data;
-  packetdata.dst_id_len = dst_id_len;
-  packetdata.dst_id_type = dst_id_type;
-  data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
-                                           packetdata.src_id_len +
-                                           packetdata.dst_id_len));
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
-    packetdata.src_id_len + dst_id_len;
-  if (type == SILC_PACKET_CONNECTION_AUTH)
-    SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen);
-  else
-    SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen);
-
-  /* Create the outgoing packet */
-  if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock,
-                            data, data_len, (const SilcBuffer)&packet)) {
-    SILC_LOG_ERROR(("Cannot assemble packet"));
-    goto out;
-  }
-
-  /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, packet.len);
-
-  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, packet.len),
-                  packet.data, packet.len);
-
-  /* Now actually send the packet */
-  silc_server_packet_send_real(server, sock, force_send);
+  SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
 
- out:
-  silc_free(packetdata.src_id);
-  silc_free(packetdata.dst_id);
+  return silc_packet_send_ext(sock, type, flags, 0, NULL, dst_id_type, dst_id,
+                             (const unsigned char *)data, data_len,
+                             NULL, NULL);
 }
 
-/* Assembles a new packet to be sent out to network. This doesn't actually
-   send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If
-   argument force_send is TRUE the packet is sent immediately and not put
-   to queue. Normal case is that the packet is not sent immediately.
-   The source and destination information is sent as argument for this
-   function. */
+/* Send packet to remote connection with specific source and destination
+   IDs. */
 
-void silc_server_packet_send_srcdest(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    SilcPacketType type,
-                                    SilcPacketFlags flags,
-                                    void *src_id,
-                                    SilcIdType src_id_type,
-                                    void *dst_id,
-                                    SilcIdType dst_id_type,
-                                    unsigned char *data,
-                                    SilcUInt32 data_len,
-                                    bool force_send)
+SilcBool silc_server_packet_send_srcdest(SilcServer server,
+                                        SilcPacketStream sock,
+                                        SilcPacketType type,
+                                        SilcPacketFlags flags,
+                                        void *src_id,
+                                        SilcIdType src_id_type,
+                                        void *dst_id,
+                                        SilcIdType dst_id_type,
+                                        unsigned char *data,
+                                        SilcUInt32 data_len)
 {
-  SilcPacketContext packetdata;
-  const SilcBufferStruct packet;
   SilcIDListData idata;
-  SilcCipher cipher = NULL;
-  SilcHmac hmac = NULL;
-  SilcUInt32 sequence = 0;
-  unsigned char *dst_id_data = NULL;
-  SilcUInt32 dst_id_len = 0;
-  unsigned char *src_id_data = NULL;
-  SilcUInt32 src_id_len = 0;
-  int block_len = 0;
-
-  SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
 
   if (!sock)
-    return;
+    return FALSE;
 
-  /* Get data used in the packet sending, keys and stuff */
-  idata = (SilcIDListData)sock->user_data;
+  idata = silc_packet_get_context(sock);
 
-  /* If entry is disabled do not sent anything.  Allow hearbeat and
-     rekeys, though */
+  /* If entry is disabled do not sent anything.  Allow hearbeat though */
   if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
-       type != SILC_PACKET_HEARTBEAT && type != SILC_PACKET_REKEY &&
-       type != SILC_PACKET_REKEY_DONE && type != SILC_PACKET_KEY_EXCHANGE_1
-       && type != SILC_PACKET_KEY_EXCHANGE_2) ||
-      (sock->user_data == server->id_entry)) {
+       type != SILC_PACKET_HEARTBEAT) ||
+      ((SilcServerEntry)idata == server->id_entry)) {
     SILC_LOG_DEBUG(("Connection is disabled"));
-    return;
-  }
-
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
-    sequence = idata->psn_send++;
-    block_len = silc_cipher_get_block_len(cipher);
-
-    /* Check for mandatory rekey */
-    if (sequence == SILC_SERVER_REKEY_THRESHOLD)
-      silc_schedule_task_add(server->schedule, sock->sock,
-                            silc_server_rekey_callback, sock, 0, 1,
-                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-  }
-
-  if (dst_id) {
-    dst_id_data = silc_id_id2str(dst_id, dst_id_type);
-    dst_id_len = silc_id_get_len(dst_id, dst_id_type);
-  }
-
-  if (src_id) {
-    src_id_data = silc_id_id2str(src_id, src_id_type);
-    src_id_len = silc_id_get_len(src_id, src_id_type);
-  }
-
-  /* Set the packet context pointers */
-  packetdata.type = type;
-  packetdata.flags = flags;
-  packetdata.src_id = src_id_data;
-  packetdata.src_id_len = src_id_len;
-  packetdata.src_id_type = src_id_type;
-  packetdata.dst_id = dst_id_data;
-  packetdata.dst_id_len = dst_id_len;
-  packetdata.dst_id_type = dst_id_type;
-  data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
-                                           packetdata.src_id_len +
-                                           dst_id_len));
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
-    packetdata.src_id_len + dst_id_len;
-  SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen);
-
-  /* Create the outgoing packet */
-  if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock, data,
-                            data_len, (const SilcBuffer)&packet)) {
-    SILC_LOG_ERROR(("Cannot assemble packe"));
-    goto out;
+    return FALSE;
   }
 
-  /* Encrypt the packet */
-  silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, packet.len);
-
-  SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, packet.len),
-                   packet.data, packet.len);
-
-  /* Now actually send the packet */
-  silc_server_packet_send_real(server, sock, force_send);
+  SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
 
- out:
-  silc_free(packetdata.src_id);
-  silc_free(packetdata.dst_id);
+  return silc_packet_send_ext(sock, type, flags, src_id_type, src_id,
+                             dst_id_type, dst_id,
+                             (const unsigned char *)data, data_len,
+                             NULL, NULL);
 }
 
 /* Broadcast received packet to our primary route. This function is used
@@ -370,94 +125,65 @@ void silc_server_packet_send_srcdest(SilcServer server,
    that the broadcast flag from the packet is checked before calling this
    function. This does not test or set the broadcast flag. */
 
-void silc_server_packet_broadcast(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketContext *packet)
+SilcBool silc_server_packet_broadcast(SilcServer server,
+                                     SilcPacketStream primary_route,
+                                     SilcPacket packet)
 {
-  SilcBuffer buffer = packet->buffer;
-  SilcIDListData idata;
-  void *id;
+  SilcServerID src_id, dst_id;
 
-  if (!sock)
-    return;
+  if (!primary_route)
+    return FALSE;
 
   SILC_LOG_DEBUG(("Broadcasting received broadcast packet"));
 
-  /* If the packet is originated from our primary route we are
-     not allowed to send the packet. */
-  id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
-  if (id && !SILC_ID_SERVER_COMPARE(id, server->router->id)) {
-    const SilcBufferStruct p;
-
-    idata = (SilcIDListData)sock->user_data;
-
-    silc_buffer_push(buffer, buffer->data - buffer->head);
-    if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
-                                  (const SilcBuffer)&p)) {
-      SILC_LOG_ERROR(("Cannot send packet"));
-      silc_free(id);
-      return;
-    }
-    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
-                       (SilcBuffer)&p, p.len);
-
-    SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1,
-                     p.len), p.data, p.len);
-
-    /* Now actually send the packet */
-    silc_server_packet_send_real(server, sock, TRUE);
-    silc_free(id);
-
-    /* Check for mandatory rekey */
-    if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
-      silc_schedule_task_add(server->schedule, sock->sock,
-                            silc_server_rekey_callback, sock, 0, 1,
-                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-    return;
+  if (!silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type,
+                     &src_id, sizeof(src_id)))
+    return FALSE;
+  if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, packet->dst_id_type,
+                     &dst_id, sizeof(dst_id)))
+    return FALSE;
+
+  /* If the packet is originated from our primary route we are not allowed
+     to send the packet. */
+  if (SILC_ID_SERVER_COMPARE(&src_id, server->router->id)) {
+    SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the "
+                   "original sender of this packet"));
+    return FALSE;
   }
 
-  SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the "
-                 "original sender of this packet"));
-  silc_free(id);
+  /* Send the packet */
+  return silc_server_packet_send_srcdest(server, primary_route, packet->type,
+                                        packet->flags, &src_id,
+                                        SILC_ID_SERVER, &dst_id,
+                                        SILC_ID_SERVER,
+                                        packet->buffer.data,
+                                        silc_buffer_len(&packet->buffer));
 }
 
 /* Routes received packet to `sock'. This is used to route the packets that
    router receives but are not destined to it. */
 
-void silc_server_packet_route(SilcServer server,
-                             SilcSocketConnection sock,
-                             SilcPacketContext *packet)
+SilcBool silc_server_packet_route(SilcServer server,
+                                 SilcPacketStream sock,
+                                 SilcPacket packet)
 {
-  SilcBuffer buffer = packet->buffer;
-  const SilcBufferStruct p;
-  SilcIDListData idata;
-
-  SILC_LOG_DEBUG(("Routing received packet"));
-
-  idata = (SilcIDListData)sock->user_data;
-
-  silc_buffer_push(buffer, buffer->data - buffer->head);
-  if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
-                                (const SilcBuffer)&p)) {
-    SILC_LOG_ERROR(("Cannot send packet"));
-    return;
-  }
-  silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-  silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
-                     (SilcBuffer)&p, p.len);
-
-  SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1,
-                  p.len), p.data, p.len);
-
-  /* Now actually send the packet */
-  silc_server_packet_send_real(server, sock, TRUE);
-
-  /* Check for mandatory rekey */
-  if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_rekey_callback, sock, 0, 1,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  SilcID src_id, dst_id;
+
+  if (!silc_id_str2id2(packet->src_id, packet->src_id_len, packet->src_id_type,
+                      &src_id))
+    return FALSE;
+  if (!silc_id_str2id2(packet->dst_id, packet->dst_id_len, packet->dst_id_type,
+                      &dst_id))
+    return FALSE;
+
+  return silc_server_packet_send_srcdest(server, sock, packet->type,
+                                        packet->flags,
+                                        SILC_ID_GET_ID(src_id),
+                                        src_id.type,
+                                        SILC_ID_GET_ID(dst_id),
+                                        dst_id.type,
+                                        packet->buffer.data,
+                                        silc_buffer_len(&packet->buffer));
 }
 
 /* This routine can be used to send a packet to table of clients provided
@@ -468,17 +194,17 @@ void silc_server_packet_send_clients(SilcServer server,
                                     SilcHashTable clients,
                                     SilcPacketType type,
                                     SilcPacketFlags flags,
-                                    bool route,
+                                    SilcBool route,
                                     unsigned char *data,
-                                    SilcUInt32 data_len,
-                                    bool force_send)
+                                    SilcUInt32 data_len)
 {
-  SilcSocketConnection sock = NULL;
+  SilcPacketStream sock = NULL;
+  SilcIDListData idata;
   SilcHashTableList htl;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcUInt32 routed_count = 0;
-  bool gone = FALSE;
+  SilcBool gone = FALSE;
   int k;
 
   if (!silc_hash_table_count(clients))
@@ -504,8 +230,9 @@ void silc_server_packet_send_clients(SilcServer server,
        continue;
 
       /* Route only once to router */
-      sock = (SilcSocketConnection)client->router->connection;
-      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      sock = client->router->connection;
+      idata = silc_packet_get_context(sock);
+      if (idata->conn_type == SILC_CONN_ROUTER) {
        if (gone)
          continue;
        gone = TRUE;
@@ -514,7 +241,7 @@ void silc_server_packet_send_clients(SilcServer server,
       /* Send the packet */
       silc_server_packet_send_dest(server, sock, type, flags,
                                   client->router->id, SILC_ID_SERVER,
-                                  data, data_len, force_send);
+                                  data, data_len);
 
       /* Mark this route routed already */
       routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
@@ -526,78 +253,18 @@ void silc_server_packet_send_clients(SilcServer server,
       continue;
 
     /* Send to locally connected client */
-    sock = (SilcSocketConnection)client->connection;
+    sock = client->connection;
     if (!sock)
       continue;
 
     silc_server_packet_send_dest(server, sock, type, flags,
                                 client->id, SILC_ID_CLIENT,
-                                data, data_len, force_send);
+                                data, data_len);
   }
   silc_hash_table_list_reset(&htl);
   silc_free(routed);
 }
 
-/* Internal routine to actually create the channel packet and send it
-   to network. This is common function in channel message sending. If
-   `channel_message' is TRUE this encrypts the message as it is strictly
-   a channel message. If FALSE normal encryption process is used. */
-
-static void
-silc_server_packet_send_to_channel_real(SilcServer server,
-                                       SilcSocketConnection sock,
-                                       SilcPacketContext *packet,
-                                       SilcCipher cipher,
-                                       SilcHmac hmac,
-                                       SilcUInt32 sequence,
-                                       unsigned char *data,
-                                       SilcUInt32 data_len,
-                                       bool channel_message,
-                                       bool force_send)
-{
-  int block_len;
-  const SilcBufferStruct p;
-
-  if (!sock)
-    return;
-
-  data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
-                                           packet->src_id_len +
-                                           packet->dst_id_len));
-  packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
-    packet->src_id_len + packet->dst_id_len;
-
-  block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
-  if (channel_message)
-    SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                       packet->src_id_len +
-                       packet->dst_id_len), block_len, packet->padlen);
-  else
-    SILC_PACKET_PADLEN(packet->truelen, block_len, packet->padlen);
-
-  /* Put the data to buffer, assemble and encrypt the packet. The packet
-     is encrypted with normal session key shared with the client, unless
-     the `channel_message' is TRUE. */
-  if (!silc_packet_assemble(packet, NULL, cipher, hmac, sock, data,
-                            data_len, (const SilcBuffer)&p)) {
-    SILC_LOG_ERROR(("Cannot assemble packet"));
-    return;
-  }
-
-  if (channel_message)
-    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p,
-                       SILC_PACKET_HEADER_LEN + packet->src_id_len +
-                       packet->dst_id_len + packet->padlen);
-  else
-    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
-
-  SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence, p.len),
-                  p.data, p.len);
-
-  /* Now actually send the packet */
-  silc_server_packet_send_real(server, sock, force_send);
-}
-
 /* This routine is used by the server to send packets to channel. The
    packet sent with this function is distributed to all clients on
    the channel. Usually this is used to send notify messages to the
@@ -609,58 +276,36 @@ silc_server_packet_send_to_channel_real(SilcServer server,
    packet is not sent clients, only servers. */
 
 void silc_server_packet_send_to_channel(SilcServer server,
-                                       SilcSocketConnection sender,
+                                       SilcPacketStream sender,
                                        SilcChannelEntry channel,
                                        SilcPacketType type,
-                                       bool route,
-                                       bool send_to_clients,
+                                       SilcBool route,
+                                       SilcBool send_to_clients,
                                        unsigned char *data,
-                                       SilcUInt32 data_len,
-                                       bool force_send)
+                                       SilcUInt32 data_len)
 {
-  SilcSocketConnection sock = NULL;
-  SilcPacketContext packetdata;
+  SilcPacketStream sock = NULL;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
   SilcIDListData idata;
   SilcUInt32 routed_count = 0;
-  bool gone = FALSE;
+  SilcBool gone = FALSE;
   int k;
 
   /* This doesn't send channel message packets */
   assert(type != SILC_PACKET_CHANNEL_MESSAGE);
 
-  /* Set the packet context pointers. */
-  packetdata.flags = 0;
-  packetdata.type = type;
-  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
-  packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
-  packetdata.src_id_type = SILC_ID_SERVER;
-  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_type = SILC_ID_CHANNEL;
-
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
   if (route && server->server_type != SILC_ROUTER && !server->standalone &&
       channel->global_users) {
-    SilcServerEntry router;
-
-    /* Get data used in packet header encryption, keys and stuff. */
-    router = server->router;
-    sock = (SilcSocketConnection)router->connection;
-    idata = (SilcIDListData)router;
-
+    sock = server->router->connection;
     if (sock != sender) {
       SILC_LOG_DEBUG(("Sending packet to router for routing"));
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key,
-                                             idata->hmac_send,
-                                             idata->psn_send++,
-                                             data, data_len, FALSE,
-                                             force_send);
+      silc_server_packet_send_dest(server, sock, type, 0, channel->id,
+                                  SILC_ID_CHANNEL, data, data_len);
     }
   }
 
@@ -696,7 +341,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
        continue;
 
       /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)client->router->connection;
+      sock = client->router->connection;
       idata = (SilcIDListData)client->router;
 
       if (sender && sock == sender)
@@ -704,7 +349,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
       /* Route only once to router. Protocol prohibits sending channel
         messages to more than one router. */
-      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      if (idata->conn_type == SILC_CONN_ROUTER) {
        if (gone)
          continue;
        gone = TRUE;
@@ -715,12 +360,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
                      (unsigned char *)""));
 
       /* Send the packet */
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key,
-                                             idata->hmac_send,
-                                             idata->psn_send++,
-                                             data, data_len, FALSE,
-                                             force_send);
+      silc_server_packet_send_dest(server, sock, type, 0, channel->id,
+                                  SILC_ID_CHANNEL, data, data_len);
 
       /* Mark this route routed already */
       routed[routed_count++] = client->router;
@@ -733,9 +374,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
     /* Send to locally connected client */
 
     /* Get data used in packet header encryption, keys and stuff. */
-    sock = (SilcSocketConnection)client->connection;
-    idata = (SilcIDListData)client;
-
+    sock = client->connection;
     if (!sock || (sender && sock == sender))
       continue;
 
@@ -744,35 +383,33 @@ void silc_server_packet_send_to_channel(SilcServer server,
                    (unsigned char *)""));
 
     /* Send the packet */
-    silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                           idata->send_key,
-                                           idata->hmac_send,
-                                           idata->psn_send++,
-                                           data, data_len, FALSE,
-                                           force_send);
+    silc_server_packet_send_dest(server, sock, type, 0, channel->id,
+                                SILC_ID_CHANNEL, data, data_len);
   }
   silc_hash_table_list_reset(&htl);
 
  out:
   silc_free(routed);
-  silc_free(packetdata.src_id);
-  silc_free(packetdata.dst_id);
 }
 
 /* This checks whether the relayed packet came from router. If it did
    then we'll need to encrypt it with the channel key. This is called
    from the silc_server_packet_relay_to_channel. */
 
-static bool
+static SilcBool
 silc_server_packet_relay_to_channel_encrypt(SilcServer server,
-                                           SilcSocketConnection sock,
+                                           SilcPacketStream sender,
                                            SilcChannelEntry channel,
                                            unsigned char *data,
                                            unsigned int data_len)
 {
+  SilcIDListData idata;
   SilcUInt32 mac_len, iv_len;
   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
   SilcUInt16 totlen, len;
+  SilcID src_id, dst_id;
+
+  idata = silc_packet_get_context(sender);
 
   /* If we are router and the packet came from router and private key
      has not been set for the channel then we must encrypt the packet
@@ -780,18 +417,18 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
      router which sent it. This is so, because cells does not share the
      same channel key. */
   if (server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      idata->conn_type == SILC_CONN_ROUTER &&
       !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) && channel->key) {
 
     /* If we are backup router and remote is our primary router and
        we are currently doing backup resuming protocol we must not
        re-encrypt message with session key. */
-    if (server->backup_router && SILC_SERVER_IS_BACKUP(sock) &&
-       SILC_PRIMARY_ROUTE(server) == sock)
+    if (server->backup_router && idata->sconn->backup_resuming &&
+       SILC_PRIMARY_ROUTE(server) == sender)
       return TRUE;
 
     mac_len = silc_hmac_len(channel->hmac);
-    iv_len = silc_cipher_get_block_len(channel->channel_key);
+    iv_len = silc_cipher_get_block_len(channel->send_key);
 
     if (data_len <= mac_len + iv_len) {
       SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
@@ -813,9 +450,15 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
     }
 
     memcpy(iv, data + (data_len - iv_len - mac_len), iv_len);
-    silc_message_payload_encrypt(data, totlen, data_len - mac_len,
-                                 iv, iv_len, channel->channel_key,
-                                channel->hmac);
+
+    src_id.type = SILC_ID_SERVER;
+    src_id.u.server_id = *((SilcServerEntry)idata)->id;
+    dst_id.type = SILC_ID_CHANNEL;
+    dst_id.u.channel_id = *channel->id;
+
+    return silc_message_payload_encrypt(data, totlen, data_len - mac_len,
+                                       iv, &src_id, &dst_id,
+                                       channel->send_key, channel->hmac);
   }
 
   return TRUE;
@@ -831,24 +474,22 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
    packet will be untouched. */
 
 void silc_server_packet_relay_to_channel(SilcServer server,
-                                        SilcSocketConnection sender_sock,
+                                        SilcPacketStream sender_sock,
                                         SilcChannelEntry channel,
                                         void *sender_id,
                                         SilcIdType sender_type,
                                         SilcClientEntry sender_entry,
                                         unsigned char *data,
-                                        SilcUInt32 data_len,
-                                        bool force_send)
+                                        SilcUInt32 data_len)
 {
-  SilcSocketConnection sock = NULL;
-  SilcPacketContext packetdata;
+  SilcPacketStream sock = NULL;
   SilcClientEntry client = NULL;
   SilcServerEntry *routed = NULL;
   SilcChannelClientEntry chl, chl_sender;
   SilcUInt32 routed_count = 0;
   SilcIDListData idata;
   SilcHashTableList htl;
-  bool gone = FALSE;
+  SilcBool gone = FALSE;
   int k;
 
   if (!silc_server_client_on_channel(sender_entry, channel, &chl_sender))
@@ -856,7 +497,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
   SILC_LOG_DEBUG(("Relaying packet to channel %s", channel->channel_name));
 
-  /* This encrypts the packet, if needed. It will be encrypted if
+  /* This encrypts the message, if needed. It will be encrypted if
      it came from the router thus it needs to be encrypted with the
      channel key. If the channel key does not exist, then we know we
      don't have a single local user on the channel. */
@@ -865,16 +506,6 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                                   data_len))
     return;
 
-  /* Set the packet context pointers. */
-  packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
-  packetdata.src_id = silc_id_id2str(sender_id, sender_type);
-  packetdata.src_id_len = silc_id_get_len(sender_id, sender_type);
-  packetdata.src_id_type = sender_type;
-  packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
-  packetdata.dst_id_type = SILC_ID_CHANNEL;
-
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
   if (server->server_type != SILC_ROUTER && !server->standalone &&
@@ -882,20 +513,14 @@ void silc_server_packet_relay_to_channel(SilcServer server,
     SilcServerEntry router = server->router;
 
     /* Check that the sender is not our router. */
-    if (sender_sock != (SilcSocketConnection)router->connection) {
-
-      /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)router->connection;
-      idata = (SilcIDListData)router;
-
+    if (sender_sock != router->connection) {
       SILC_LOG_DEBUG(("Sending message to router for routing"));
-
-      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key,
-                                             idata->hmac_send,
-                                             idata->psn_send++,
-                                             data, data_len, TRUE,
-                                             force_send);
+      sock = router->connection;
+      silc_server_packet_send_srcdest(server, sock,
+                                     SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                     sender_id, sender_type,
+                                     channel->id, SILC_ID_CHANNEL,
+                                     data, data_len);
     }
   }
 
@@ -936,7 +561,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        continue;
 
       /* Get data used in packet header encryption, keys and stuff. */
-      sock = (SilcSocketConnection)client->router->connection;
+      sock = client->router->connection;
       idata = (SilcIDListData)client->router;
 
       /* Check if the sender socket is the same as this client's router
@@ -944,14 +569,13 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       if (sender_sock && sock == sender_sock)
        continue;
 
-      SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)",
-                     silc_id_render(client->id, SILC_ID_CLIENT),
-                     sock->hostname, sock->ip));
+      SILC_LOG_DEBUG(("Relaying packet to client ID(%s)",
+                     silc_id_render(client->id, SILC_ID_CLIENT)));
 
       /* Mark this route routed already. */
       routed[routed_count++] = client->router;
 
-      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      if (idata->conn_type == SILC_CONN_ROUTER) {
        /* The remote connection is router then we'll decrypt the
           channel message and re-encrypt it with the session key shared
           between us and the remote router. This is done because the
@@ -967,14 +591,13 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        /* If we are backup router and remote is our primary router and
           we are currently doing backup resuming protocol we must not
           re-encrypt message with session key. */
-       if (server->backup_router && SILC_SERVER_IS_BACKUP(sock) &&
+       if (server->backup_router && idata->sconn->backup_resuming &&
            SILC_PRIMARY_ROUTE(server) == sock) {
-         silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                                 idata->send_key,
-                                                 idata->hmac_send,
-                                                 idata->psn_send++,
-                                                 data, data_len, TRUE,
-                                                 force_send);
+         silc_server_packet_send_srcdest(server, sock,
+                                         SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                         sender_id, sender_type,
+                                         channel->id, SILC_ID_CHANNEL,
+                                         data, data_len);
          continue;
        }
 
@@ -983,24 +606,29 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        /* If private key mode is not set then decrypt the packet
           and re-encrypt it */
        if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
-           channel->channel_key) {
-         unsigned char tmp[SILC_PACKET_MAX_LEN];
+           channel->receive_key) {
+         unsigned char tmp[SILC_PACKET_MAX_LEN], sid[32], rid[32];
+         SilcUInt32 sid_len, rid_len;
 
          if (data_len > SILC_PACKET_MAX_LEN)
            data_len = SILC_PACKET_MAX_LEN;
          memcpy(tmp, data, data_len);
 
          /* Decrypt the channel message (we don't check the MAC) */
+         silc_id_id2str(sender_id, sender_type, sid, sizeof(sid), &sid_len);
+         silc_id_id2str(channel->id, SILC_ID_CHANNEL, rid, sizeof(rid),
+                        &rid_len);
          silc_message_payload_decrypt(tmp, data_len, FALSE, FALSE,
-                                      channel->channel_key,
-                                      channel->hmac, FALSE);
+                                      channel->receive_key,
+                                      channel->hmac, sid, sid_len,
+                                      rid, rid_len, FALSE);
 
          /* Now re-encrypt and send it to the router */
          silc_server_packet_send_srcdest(server, sock,
                                          SILC_PACKET_CHANNEL_MESSAGE, 0,
                                          sender_id, sender_type,
                                          channel->id, SILC_ID_CHANNEL,
-                                         tmp, data_len, force_send);
+                                         tmp, data_len);
        } else {
          /* Private key mode is set, we don't have the channel key, so
             just re-encrypt the entire packet and send it to the router. */
@@ -1008,16 +636,15 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                          SILC_PACKET_CHANNEL_MESSAGE, 0,
                                          sender_id, sender_type,
                                          channel->id, SILC_ID_CHANNEL,
-                                         data, data_len, force_send);
+                                         data, data_len);
        }
       } else {
        /* Send the packet to normal server */
-       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key,
-                                               idata->hmac_send,
-                                               idata->psn_send++,
-                                               data, data_len, TRUE,
-                                               force_send);
+       silc_server_packet_send_srcdest(server, sock,
+                                       SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                       sender_id, sender_type,
+                                       channel->id, SILC_ID_CHANNEL,
+                                       data, data_len);
       }
 
       continue;
@@ -1027,29 +654,23 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       continue;
 
     /* Get data used in packet header encryption, keys and stuff. */
-    sock = (SilcSocketConnection)client->connection;
-    idata = (SilcIDListData)client;
-
+    sock = client->connection;
     if (!sock || (sender_sock && sock == sender_sock))
       continue;
 
-    SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)",
-                   silc_id_render(client->id, SILC_ID_CLIENT),
-                   sock->hostname, sock->ip));
+    SILC_LOG_DEBUG(("Sending packet to client ID(%s)",
+                   silc_id_render(client->id, SILC_ID_CLIENT)));
 
     /* Send the packet */
-    silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                           idata->send_key,
-                                           idata->hmac_send,
-                                           idata->psn_send++,
-                                           data, data_len, TRUE,
-                                           force_send);
+    silc_server_packet_send_srcdest(server, sock,
+                                   SILC_PACKET_CHANNEL_MESSAGE, 0,
+                                   sender_id, sender_type,
+                                   channel->id, SILC_ID_CHANNEL,
+                                   data, data_len);
   }
 
   silc_hash_table_list_reset(&htl);
   silc_free(routed);
-  silc_free(packetdata.src_id);
-  silc_free(packetdata.dst_id);
 }
 
 /* This function is used to send packets strictly to all local clients
@@ -1064,12 +685,11 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                           SilcPacketType type,
                                           SilcPacketFlags flags,
                                           unsigned char *data,
-                                          SilcUInt32 data_len,
-                                          bool force_send)
+                                          SilcUInt32 data_len)
 {
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
-  SilcSocketConnection sock = NULL;
+  SilcPacketStream sock = NULL;
 
   SILC_LOG_DEBUG(("Send packet to local clients on channel %s",
                  channel->channel_name));
@@ -1082,63 +702,16 @@ void silc_server_packet_send_local_channel(SilcServer server,
 
       /* Send the packet to the client */
       silc_server_packet_send_dest(server, sock, type, flags, chl->client->id,
-                                  SILC_ID_CLIENT, data, data_len,
-                                  force_send);
+                                  SILC_ID_CLIENT, data, data_len);
     }
   }
   silc_hash_table_list_reset(&htl);
 }
 
-/* Routine used to send (relay, route) private messages to some destination.
-   If the private message key does not exist then the message is re-encrypted,
-   otherwise we just pass it along. This really is not used to send new
-   private messages (as server does not send them) but to relay received
-   private messages. */
-
-void silc_server_send_private_message(SilcServer server,
-                                     SilcSocketConnection dst_sock,
-                                     SilcCipher cipher,
-                                     SilcHmac hmac,
-                                     SilcUInt32 sequence,
-                                     SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  const SilcBufferStruct p;
-
-  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
-                  + packet->dst_id_len + packet->padlen);
-  if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len, hmac,
-                                (const SilcBuffer)&p)) {
-    SILC_LOG_ERROR(("Cannot send packet"));
-    return;
-  }
-  silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-
-  /* Re-encrypt and send if private messge key does not exist */
-  if (!(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY)) {
-    /* Re-encrypt packet */
-    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, buffer->len);
-  } else {
-    /* Key exist so encrypt just header and send it */
-    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p,
-                       SILC_PACKET_HEADER_LEN + packet->src_id_len +
-                       packet->dst_id_len + packet->padlen);
-  }
-
-  /* Send the packet */
-  silc_server_packet_send_real(server, dst_sock, FALSE);
-
-  /* Check for mandatory rekey */
-  if (sequence == SILC_SERVER_REKEY_THRESHOLD)
-    silc_schedule_task_add(server->schedule, dst_sock->sock,
-                          silc_server_rekey_callback, dst_sock, 0, 1,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-}
-
 /* Sends current motd to client */
 
 void silc_server_send_motd(SilcServer server,
-                          SilcSocketConnection sock)
+                          SilcPacketStream sock)
 {
   char *motd, *motd_file = NULL;
   SilcUInt32 motd_len;
@@ -1162,7 +735,7 @@ void silc_server_send_motd(SilcServer server,
    implications. */
 
 void silc_server_send_error(SilcServer server,
-                           SilcSocketConnection sock,
+                           SilcPacketStream sock,
                            const char *fmt, ...)
 {
   va_list ap;
@@ -1174,7 +747,7 @@ void silc_server_send_error(SilcServer server,
   va_end(ap);
 
   silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0,
-                         buf, strlen(buf), FALSE);
+                         buf, strlen(buf));
 }
 
 /* Sends notify message. If format is TRUE the variable arguments are
@@ -1183,8 +756,8 @@ void silc_server_send_error(SilcServer server,
    in the argument list must be { argument data, argument length }. */
 
 void silc_server_send_notify(SilcServer server,
-                            SilcSocketConnection sock,
-                            bool broadcast,
+                            SilcPacketStream sock,
+                            SilcBool broadcast,
                             SilcNotifyType type,
                             SilcUInt32 argc, ...)
 {
@@ -1196,7 +769,7 @@ void silc_server_send_notify(SilcServer server,
   packet = silc_notify_payload_encode(type, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
-                         packet->data, packet->len, FALSE);
+                         packet->data, silc_buffer_len(packet));
 
   /* Send to backup routers if this is being broadcasted to primary
      router.  The silc_server_backup_send checks further whether to
@@ -1204,7 +777,8 @@ void silc_server_send_notify(SilcServer server,
   if ((broadcast && sock && sock == SILC_PRIMARY_ROUTE(server)) ||
       (broadcast && !sock && !SILC_PRIMARY_ROUTE(server)))
     silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0,
-                           packet->data, packet->len, FALSE, TRUE);
+                           packet->data, silc_buffer_len(packet),
+                           FALSE, TRUE);
 
   silc_buffer_free(packet);
   va_end(ap);
@@ -1214,8 +788,8 @@ void silc_server_send_notify(SilcServer server,
    Payloads. */
 
 void silc_server_send_notify_args(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  SilcNotifyType type,
                                  SilcUInt32 argc,
                                  SilcBuffer args)
@@ -1225,7 +799,7 @@ void silc_server_send_notify_args(SilcServer server,
   packet = silc_notify_payload_encode_args(type, argc, args);
   silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
-                         packet->data, packet->len, FALSE);
+                         packet->data, silc_buffer_len(packet));
   silc_buffer_free(packet);
 }
 
@@ -1233,8 +807,8 @@ void silc_server_send_notify_args(SilcServer server,
    `old_id' with the `new_id'. */
 
 void silc_server_send_notify_channel_change(SilcServer server,
-                                           SilcSocketConnection sock,
-                                           bool broadcast,
+                                           SilcPacketStream sock,
+                                           SilcBool broadcast,
                                            SilcChannelID *old_id,
                                            SilcChannelID *new_id)
 {
@@ -1245,7 +819,8 @@ void silc_server_send_notify_channel_change(SilcServer server,
 
   silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_CHANNEL_CHANGE,
-                         2, idp1->data, idp1->len, idp2->data, idp2->len);
+                         2, idp1->data, silc_buffer_len(idp1),
+                         idp2->data, silc_buffer_len(idp2));
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
 }
@@ -1254,8 +829,8 @@ void silc_server_send_notify_channel_change(SilcServer server,
    `old_id' with the `new_id'. */
 
 void silc_server_send_notify_nick_change(SilcServer server,
-                                        SilcSocketConnection sock,
-                                        bool broadcast,
+                                        SilcPacketStream sock,
+                                        SilcBool broadcast,
                                         SilcClientID *old_id,
                                         SilcClientID *new_id,
                                         const char *nickname)
@@ -1267,7 +842,8 @@ void silc_server_send_notify_nick_change(SilcServer server,
 
   silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_NICK_CHANGE,
-                         3, idp1->data, idp1->len, idp2->data, idp2->len,
+                         3, idp1->data, silc_buffer_len(idp1),
+                         idp2->data, silc_buffer_len(idp2),
                          nickname, nickname ? strlen(nickname) : 0);
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
@@ -1277,8 +853,8 @@ void silc_server_send_notify_nick_change(SilcServer server,
    has joined to the `channel'. */
 
 void silc_server_send_notify_join(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  SilcChannelEntry channel,
                                  SilcClientID *client_id)
 {
@@ -1287,8 +863,8 @@ void silc_server_send_notify_join(SilcServer server,
   idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
   idp2 = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
   silc_server_send_notify(server, sock, broadcast, SILC_NOTIFY_TYPE_JOIN,
-                         2, idp1->data, idp1->len,
-                         idp2->data, idp2->len);
+                         2, idp1->data, silc_buffer_len(idp1),
+                         idp2->data, silc_buffer_len(idp2));
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
 }
@@ -1297,8 +873,8 @@ void silc_server_send_notify_join(SilcServer server,
    `channel'. The Notify packet is always destined to the channel. */
 
 void silc_server_send_notify_leave(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  bool broadcast,
+                                  SilcPacketStream sock,
+                                  SilcBool broadcast,
                                   SilcChannelEntry channel,
                                   SilcClientID *client_id)
 {
@@ -1307,7 +883,7 @@ void silc_server_send_notify_leave(SilcServer server,
   idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_LEAVE,
-                              1, idp->data, idp->len);
+                              1, idp->data, silc_buffer_len(idp));
   silc_buffer_free(idp);
 }
 
@@ -1316,8 +892,8 @@ void silc_server_send_notify_leave(SilcServer server,
    the channel. */
 
 void silc_server_send_notify_cmode(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  bool broadcast,
+                                  SilcPacketStream sock,
+                                  SilcBool broadcast,
                                   SilcChannelEntry channel,
                                   SilcUInt32 mode_mask,
                                   void *id, SilcIdType id_type,
@@ -1332,21 +908,23 @@ void silc_server_send_notify_cmode(SilcServer server,
   idp = silc_id_payload_encode((void *)id, id_type);
   SILC_PUT32_MSB(mode_mask, mode);
   if (founder_key)
-    fkey = silc_pkcs_public_key_payload_encode(founder_key);
+    fkey = silc_public_key_payload_encode(founder_key);
   if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
     SILC_PUT32_MSB(channel->user_limit, ulimit);
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              8, idp->data, idp->len,
+                              8, idp->data, silc_buffer_len(idp),
                               mode, 4,
                               cipher, cipher ? strlen(cipher) : 0,
                               hmac, hmac ? strlen(hmac) : 0,
                               passphrase, passphrase ?
                               strlen(passphrase) : 0,
-                              fkey ? fkey->data : NULL, fkey ? fkey->len : 0,
+                              fkey ? fkey->data : NULL,
+                              fkey ? silc_buffer_len(fkey) : 0,
                               channel_pubkeys ? channel_pubkeys->data : NULL,
-                              channel_pubkeys ? channel_pubkeys->len : 0,
+                              channel_pubkeys ?
+                              silc_buffer_len(channel_pubkeys) : 0,
                               mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
                               ulimit : NULL,
                               mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
@@ -1360,8 +938,8 @@ void silc_server_send_notify_cmode(SilcServer server,
    destined to the channel. */
 
 void silc_server_send_notify_cumode(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcChannelEntry channel,
                                    SilcUInt32 mode_mask,
                                    void *id, SilcIdType id_type,
@@ -1375,15 +953,16 @@ void silc_server_send_notify_cumode(SilcServer server,
   idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT);
   SILC_PUT32_MSB(mode_mask, mode);
   if (founder_key)
-    fkey = silc_pkcs_public_key_payload_encode(founder_key);
+    fkey = silc_public_key_payload_encode(founder_key);
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL,
                               SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
-                              idp1->data, idp1->len,
+                              idp1->data, silc_buffer_len(idp1),
                               mode, 4,
-                              idp2->data, idp2->len,
-                              fkey ? fkey->data : NULL, fkey ? fkey->len : 0);
+                              idp2->data, silc_buffer_len(idp2),
+                              fkey ? fkey->data : NULL,
+                              fkey ? silc_buffer_len(fkey) : 0);
   silc_buffer_free(fkey);
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
@@ -1395,8 +974,8 @@ void silc_server_send_notify_cumode(SilcServer server,
    client. The `message may be NULL. */
 
 void silc_server_send_notify_signoff(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    bool broadcast,
+                                    SilcPacketStream sock,
+                                    SilcBool broadcast,
                                     SilcClientID *client_id,
                                     const char *message)
 {
@@ -1405,7 +984,7 @@ void silc_server_send_notify_signoff(SilcServer server,
   idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
   silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_SIGNOFF,
-                         message ? 2 : 1, idp->data, idp->len,
+                         message ? 2 : 1, idp->data, silc_buffer_len(idp),
                          message, message ? strlen(message): 0);
   silc_buffer_free(idp);
 }
@@ -1416,8 +995,8 @@ void silc_server_send_notify_signoff(SilcServer server,
    between routers. */
 
 void silc_server_send_notify_topic_set(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      bool broadcast,
+                                      SilcPacketStream sock,
+                                      SilcBool broadcast,
                                       SilcChannelEntry channel,
                                       void *id, SilcIdType id_type,
                                       char *topic)
@@ -1429,7 +1008,7 @@ void silc_server_send_notify_topic_set(SilcServer server,
                               (void *)channel->id, SILC_ID_CHANNEL,
                               SILC_NOTIFY_TYPE_TOPIC_SET,
                               topic ? 2 : 1,
-                              idp->data, idp->len,
+                              idp->data, silc_buffer_len(idp),
                               topic, topic ? strlen(topic) : 0);
   silc_buffer_free(idp);
 }
@@ -1440,8 +1019,8 @@ void silc_server_send_notify_topic_set(SilcServer server,
    traffic. */
 
 void silc_server_send_notify_kicked(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcChannelEntry channel,
                                    SilcClientID *client_id,
                                    SilcClientID *kicker,
@@ -1454,9 +1033,9 @@ void silc_server_send_notify_kicked(SilcServer server,
   idp2 = silc_id_payload_encode((void *)kicker, SILC_ID_CLIENT);
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED, 3,
-                              idp1->data, idp1->len,
+                              idp1->data, silc_buffer_len(idp1),
                               comment, comment ? strlen(comment) : 0,
-                              idp2->data, idp2->len);
+                              idp2->data, silc_buffer_len(idp2));
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
 }
@@ -1466,8 +1045,8 @@ void silc_server_send_notify_kicked(SilcServer server,
    for the killing. */
 
 void silc_server_send_notify_killed(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcClientID *client_id,
                                    const char *comment,
                                    void *killer, SilcIdType killer_type)
@@ -1479,9 +1058,9 @@ void silc_server_send_notify_killed(SilcServer server,
   idp2 = silc_id_payload_encode(killer, killer_type);
   silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id,
                               SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED,
-                              3, idp1->data, idp1->len,
+                              3, idp1->data, silc_buffer_len(idp1),
                               comment, comment ? strlen(comment) : 0,
-                              idp2->data, idp2->len);
+                              idp2->data, silc_buffer_len(idp2));
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
 }
@@ -1491,8 +1070,8 @@ void silc_server_send_notify_killed(SilcServer server,
    send the packet between routers as broadcast packet. */
 
 void silc_server_send_notify_umode(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  bool broadcast,
+                                  SilcPacketStream sock,
+                                  SilcBool broadcast,
                                   SilcClientID *client_id,
                                   SilcUInt32 mode_mask)
 {
@@ -1504,7 +1083,7 @@ void silc_server_send_notify_umode(SilcServer server,
 
   silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_UMODE_CHANGE, 2,
-                         idp->data, idp->len,
+                         idp->data, silc_buffer_len(idp),
                          mode, 4);
   silc_buffer_free(idp);
 }
@@ -1514,8 +1093,8 @@ void silc_server_send_notify_umode(SilcServer server,
    between routers as broadcast packet. */
 
 void silc_server_send_notify_ban(SilcServer server,
-                                SilcSocketConnection sock,
-                                bool broadcast,
+                                SilcPacketStream sock,
+                                SilcBool broadcast,
                                 SilcChannelEntry channel,
                                 unsigned char *action,
                                 SilcBuffer list)
@@ -1525,9 +1104,10 @@ void silc_server_send_notify_ban(SilcServer server,
   idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
   silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_BAN, 3,
-                         idp->data, idp->len,
+                         idp->data, silc_buffer_len(idp),
                          action ? action : NULL, action ? 1 : 0,
-                         list ? list->data : NULL, list ? list->len : 0);
+                         list ? list->data : NULL,
+                         list ? silc_buffer_len(list) : 0);
   silc_buffer_free(idp);
 }
 
@@ -1537,8 +1117,8 @@ void silc_server_send_notify_ban(SilcServer server,
    packet. */
 
 void silc_server_send_notify_invite(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcChannelEntry channel,
                                    SilcClientID *client_id,
                                    unsigned char *action,
@@ -1550,11 +1130,12 @@ void silc_server_send_notify_invite(SilcServer server,
   idp2 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
   silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_INVITE, 5,
-                         idp->data, idp->len,
+                         idp->data, silc_buffer_len(idp),
                          channel->channel_name, strlen(channel->channel_name),
-                         idp2->data, idp2->len,
+                         idp2->data, silc_buffer_len(idp2),
                          action ? action : NULL, action ? 1 : 0,
-                         list ? list->data : NULL, list ? list->len : 0);
+                         list ? list->data : NULL,
+                         list ? silc_buffer_len(list) : 0);
   silc_buffer_free(idp);
   silc_buffer_free(idp2);
 }
@@ -1563,7 +1144,7 @@ void silc_server_send_notify_invite(SilcServer server,
    its status in the network has changed. */
 
 void silc_server_send_notify_watch(SilcServer server,
-                                  SilcSocketConnection sock,
+                                  SilcPacketStream sock,
                                   SilcClientEntry watcher,
                                   SilcClientEntry client,
                                   const char *nickname,
@@ -1577,16 +1158,16 @@ void silc_server_send_notify_watch(SilcServer server,
   SILC_PUT16_MSB(type, n);
   SILC_PUT32_MSB(client->mode, mode);
   if (public_key)
-    pkp = silc_pkcs_public_key_payload_encode(public_key);
+    pkp = silc_public_key_payload_encode(public_key);
   silc_server_send_notify_dest(server, sock, FALSE, watcher->id,
                               SILC_ID_CLIENT, SILC_NOTIFY_TYPE_WATCH,
-                              5, idp->data, idp->len,
+                              5, idp->data, silc_buffer_len(idp),
                               nickname, nickname ? strlen(nickname) : 0,
                               mode, sizeof(mode),
                               type != SILC_NOTIFY_TYPE_NONE ?
                               n : NULL, sizeof(n),
                               pkp ? pkp->data : NULL,
-                              pkp ? pkp->len : 0);
+                              pkp ? silc_buffer_len(pkp) : 0);
   silc_buffer_free(idp);
   silc_buffer_free(pkp);
 }
@@ -1594,8 +1175,8 @@ void silc_server_send_notify_watch(SilcServer server,
 /* Sends notify message destined to specific entity. */
 
 void silc_server_send_notify_dest(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
@@ -1610,7 +1191,7 @@ void silc_server_send_notify_dest(SilcServer server,
   silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY,
                               broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                               dest_id, dest_id_type,
-                              packet->data, packet->len, FALSE);
+                              packet->data, silc_buffer_len(packet));
 
   /* Send to backup routers if this is being broadcasted to primary
      router.  The silc_server_backup_send checks further whether to
@@ -1619,7 +1200,8 @@ void silc_server_send_notify_dest(SilcServer server,
       (broadcast && !sock && !SILC_PRIMARY_ROUTE(server)))
     silc_server_backup_send_dest(server, NULL, SILC_PACKET_NOTIFY, 0,
                                 dest_id, dest_id_type,
-                                packet->data, packet->len, FALSE, TRUE);
+                                packet->data, silc_buffer_len(packet),
+                                FALSE, TRUE);
 
   silc_buffer_free(packet);
   va_end(ap);
@@ -1633,10 +1215,10 @@ void silc_server_send_notify_dest(SilcServer server,
    originally came from it. */
 
 void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcSocketConnection sender,
+                                       SilcPacketStream sender,
                                        SilcChannelEntry channel,
-                                       bool route_notify,
-                                       bool send_to_clients,
+                                       SilcBool route_notify,
+                                       SilcBool send_to_clients,
                                        SilcNotifyType type,
                                        SilcUInt32 argc, ...)
 {
@@ -1649,7 +1231,7 @@ void silc_server_send_notify_to_channel(SilcServer server,
   silc_server_packet_send_to_channel(server, sender, channel,
                                     SILC_PACKET_NOTIFY, route_notify,
                                     send_to_clients,
-                                    packet->data, packet->len, FALSE);
+                                    packet->data, silc_buffer_len(packet));
   silc_buffer_free(packet);
   va_end(ap);
 }
@@ -1668,8 +1250,7 @@ void silc_server_send_notify_on_channels(SilcServer server,
                                         SilcUInt32 argc, ...)
 {
   int k;
-  SilcSocketConnection sock = NULL;
-  SilcPacketContext packetdata;
+  SilcPacketStream sock = NULL;
   SilcClientEntry c;
   SilcClientEntry *sent_clients = NULL;
   SilcUInt32 sent_clients_count = 0;
@@ -1678,11 +1259,9 @@ void silc_server_send_notify_on_channels(SilcServer server,
   SilcHashTableList htl, htl2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl, chl2;
-  SilcIDListData idata;
   SilcBuffer packet;
   unsigned char *data;
   SilcUInt32 data_len;
-  bool force_send = FALSE;
   va_list ap;
 
   if (!silc_hash_table_count(client->channels)) {
@@ -1695,14 +1274,7 @@ void silc_server_send_notify_on_channels(SilcServer server,
   va_start(ap, argc);
   packet = silc_notify_payload_encode(type, argc, ap);
   data = packet->data;
-  data_len = packet->len;
-
-  /* Set the packet context pointers. */
-  packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_NOTIFY;
-  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
-  packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
-  packetdata.src_id_type = SILC_ID_SERVER;
+  data_len = silc_buffer_len(packet);
 
   silc_hash_table_list(client->channels, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
@@ -1734,31 +1306,12 @@ void silc_server_send_notify_on_channels(SilcServer server,
        if (k < routed_count)
          continue;
 
-       /* Get data used in packet header encryption, keys and stuff. */
-       sock = (SilcSocketConnection)c->router->connection;
-       idata = (SilcIDListData)c->router;
-
-       {
-         SILC_LOG_DEBUG(("*****************"));
-         SILC_LOG_DEBUG(("client->router->id %s",
-                         silc_id_render(c->router->id, SILC_ID_SERVER)));
-         SILC_LOG_DEBUG(("client->router->connection->user_data->id %s",
-                         silc_id_render(((SilcServerEntry)sock->user_data)->id, SILC_ID_SERVER)));
-       }
-
-       packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
-       packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER);
-       packetdata.dst_id_type = SILC_ID_SERVER;
+       sock = c->router->connection;
 
        /* Send the packet */
-       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key,
-                                               idata->hmac_send,
-                                               idata->psn_send++,
-                                               data, data_len, FALSE,
-                                               force_send);
-
-       silc_free(packetdata.dst_id);
+       silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0,
+                                    c->router->id, SILC_ID_SERVER,
+                                    data, data_len);
 
        /* We want to make sure that the packet is routed to same router
           only once. Mark this route as sent route. */
@@ -1772,27 +1325,13 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
       /* Send to locally connected client */
       if (c) {
-
-       /* Get data used in packet header encryption, keys and stuff. */
-       sock = (SilcSocketConnection)c->connection;
-       idata = (SilcIDListData)c;
-
+       sock = c->connection;
         if (!sock)
           continue;
 
-       packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
-       packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
-       packetdata.dst_id_type = SILC_ID_CLIENT;
-
        /* Send the packet */
-       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key,
-                                               idata->hmac_send,
-                                               idata->psn_send++,
-                                               data, data_len, FALSE,
-                                               force_send);
-
-       silc_free(packetdata.dst_id);
+       silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0,
+                                    c->id, SILC_ID_CLIENT, data, data_len);
 
        /* Make sure that we send the notify only once per client. */
        sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) *
@@ -1806,7 +1345,6 @@ void silc_server_send_notify_on_channels(SilcServer server,
   silc_hash_table_list_reset(&htl);
   silc_free(routed);
   silc_free(sent_clients);
-  silc_free(packetdata.src_id);
   silc_buffer_free(packet);
   va_end(ap);
 }
@@ -1818,8 +1356,8 @@ void silc_server_send_notify_on_channels(SilcServer server,
    broadcast packet. */
 
 void silc_server_send_new_id(SilcServer server,
-                            SilcSocketConnection sock,
-                            bool broadcast,
+                            SilcPacketStream sock,
+                            SilcBool broadcast,
                             void *id, SilcIdType id_type,
                             SilcUInt32 id_len)
 {
@@ -1830,7 +1368,7 @@ void silc_server_send_new_id(SilcServer server,
   idp = silc_id_payload_encode(id, id_type);
   silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
-                         idp->data, idp->len, FALSE);
+                         idp->data, silc_buffer_len(idp));
   silc_buffer_free(idp);
 }
 
@@ -1839,21 +1377,21 @@ void silc_server_send_new_id(SilcServer server,
    about new channel. This packet is broadcasted by router. */
 
 void silc_server_send_new_channel(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  char *channel_name,
                                  void *channel_id,
                                  SilcUInt32 channel_id_len,
                                  SilcUInt32 mode)
 {
   SilcBuffer packet;
-  unsigned char *cid;
+  unsigned char cid[32];
   SilcUInt32 name_len = strlen(channel_name);
 
   SILC_LOG_DEBUG(("Sending new channel"));
 
-  cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
-  if (!cid)
+  if (!silc_id_id2str(channel_id, SILC_ID_CHANNEL, cid, sizeof(cid),
+                     &channel_id_len))
     return;
 
   /* Encode the channel payload */
@@ -1862,9 +1400,8 @@ void silc_server_send_new_channel(SilcServer server,
 
   silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
-                         packet->data, packet->len, FALSE);
+                         packet->data, silc_buffer_len(packet));
 
-  silc_free(cid);
   silc_buffer_free(packet);
 }
 
@@ -1878,44 +1415,41 @@ void silc_server_send_new_channel(SilcServer server,
    it originally came from it. */
 
 void silc_server_send_channel_key(SilcServer server,
-                                 SilcSocketConnection sender,
+                                 SilcPacketStream sender,
                                  SilcChannelEntry channel,
                                  unsigned char route)
 {
   SilcBuffer packet;
-  unsigned char *chid;
-  SilcUInt32 tmp_len;
+  unsigned char cid[32];
+  SilcUInt32 tmp_len, cid_len;
   const char *cipher;
 
   SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name));
 
-  chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-  if (!chid)
+  if (!channel->key)
     return;
 
-  if (!channel->channel_key)
+  if (!silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid),
+                     &cid_len))
     return;
 
   /* Encode channel key packet */
-  cipher = silc_cipher_get_name(channel->channel_key);
+  cipher = silc_cipher_get_name(channel->send_key);
   tmp_len = strlen(cipher);
-  packet = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
-                                                          SILC_ID_CHANNEL),
-                                          chid, tmp_len, cipher,
+  packet = silc_channel_key_payload_encode(cid_len, cid, tmp_len, cipher,
                                            channel->key_len / 8, channel->key);
   silc_server_packet_send_to_channel(server, sender, channel,
                                     SILC_PACKET_CHANNEL_KEY,
-                                     route, TRUE, packet->data, packet->len,
-                                    FALSE);
+                                     route, TRUE, packet->data,
+                                    silc_buffer_len(packet));
   silc_buffer_free(packet);
-  silc_free(chid);
 }
 
 /* Generic function to send any command. The arguments must be sent already
    encoded into correct form in correct order. */
 
 void silc_server_send_command(SilcServer server,
-                             SilcSocketConnection sock,
+                             SilcPacketStream sock,
                              SilcCommand command,
                              SilcUInt16 ident,
                              SilcUInt32 argc, ...)
@@ -1930,7 +1464,7 @@ void silc_server_send_command(SilcServer server,
 
   packet = silc_command_payload_encode_vap(command, ident, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
-                         packet->data, packet->len, FALSE);
+                         packet->data, silc_buffer_len(packet));
   silc_buffer_free(packet);
   va_end(ap);
 }
@@ -1939,7 +1473,7 @@ void silc_server_send_command(SilcServer server,
    already encoded into correct form in correct order. */
 
 void silc_server_send_command_reply(SilcServer server,
-                                   SilcSocketConnection sock,
+                                   SilcPacketStream sock,
                                    SilcCommand command,
                                    SilcStatus status,
                                    SilcStatus error,
@@ -1957,7 +1491,7 @@ void silc_server_send_command_reply(SilcServer server,
   packet = silc_command_reply_payload_encode_vap(command, status, error,
                                                 ident, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
-                         packet->data, packet->len, FALSE);
+                         packet->data, silc_buffer_len(packet));
   silc_buffer_free(packet);
   va_end(ap);
 }
@@ -1966,7 +1500,7 @@ void silc_server_send_command_reply(SilcServer server,
    already encoded into correct form in correct order. */
 
 void silc_server_send_dest_command_reply(SilcServer server,
-                                        SilcSocketConnection sock,
+                                        SilcPacketStream sock,
                                         void *dst_id,
                                         SilcIdType dst_id_type,
                                         SilcCommand command,
@@ -1987,113 +1521,32 @@ void silc_server_send_dest_command_reply(SilcServer server,
                                                 ident, argc, ap);
   silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
                               dst_id, dst_id_type, packet->data,
-                              packet->len, FALSE);
+                              silc_buffer_len(packet));
   silc_buffer_free(packet);
   va_end(ap);
 }
 
-/* Send the heartbeat packet. */
-
-void silc_server_send_heartbeat(SilcServer server,
-                               SilcSocketConnection sock)
-{
-  silc_server_packet_send(server, sock, SILC_PACKET_HEARTBEAT, 0,
-                         NULL, 0, FALSE);
-}
-
-/* Generic function to relay packet we've received. This is used to relay
-   packets to a client but generally can be used to other purposes as well. */
-
-void silc_server_relay_packet(SilcServer server,
-                             SilcSocketConnection dst_sock,
-                             SilcCipher cipher,
-                             SilcHmac hmac,
-                             SilcUInt32 sequence,
-                             SilcPacketContext *packet,
-                             bool force_send)
-{
-  const SilcBufferStruct p;
-
-  silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
-                  + packet->dst_id_len + packet->padlen);
-  if (!silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len, hmac,
-                                (const SilcBuffer)&p)) {
-    SILC_LOG_ERROR(("Cannot send packet"));
-    return;
-  }
-  silc_buffer_put((SilcBuffer)&p, packet->buffer->data, packet->buffer->len);
-
-  /* Re-encrypt packet */
-  silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
-
-  /* Send the packet */
-  silc_server_packet_send_real(server, dst_sock, force_send);
-
-  silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
-                  + packet->dst_id_len + packet->padlen);
-
-  /* Check for mandatory rekey */
-  if (sequence == SILC_SERVER_REKEY_THRESHOLD)
-    silc_schedule_task_add(server->schedule, dst_sock->sock,
-                          silc_server_rekey_callback, dst_sock, 0, 1,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-}
-
 /* Routine used to send the connection authentication packet. */
 
 void silc_server_send_connection_auth_request(SilcServer server,
-                                             SilcSocketConnection sock,
+                                             SilcPacketStream sock,
                                              SilcUInt16 conn_type,
                                              SilcAuthMethod auth_meth)
 {
   SilcBuffer packet;
 
   packet = silc_buffer_alloc(4);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_pull_tail(packet, silc_buffer_truelen(packet));
   silc_buffer_format(packet,
                     SILC_STR_UI_SHORT(conn_type),
                     SILC_STR_UI_SHORT(auth_meth),
                     SILC_STR_END);
 
   silc_server_packet_send(server, sock, SILC_PACKET_CONNECTION_AUTH_REQUEST,
-                         0, packet->data, packet->len, FALSE);
+                         0, packet->data, silc_buffer_len(packet));
   silc_buffer_free(packet);
 }
 
-/* Purge the outgoing packet queue to the network if there is data. This
-   function can be used to empty the packet queue. */
-
-void silc_server_packet_queue_purge(SilcServer server,
-                                   SilcSocketConnection sock)
-{
-  if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
-      !(SILC_IS_DISCONNECTING(sock)) && !(SILC_IS_DISCONNECTED(sock))) {
-    int ret;
-
-    SILC_LOG_DEBUG(("Purging outgoing queue"));
-
-    server->stat.packets_sent++;
-    ret = silc_packet_send(sock, TRUE);
-    if (ret == -2) {
-      if (sock->outbuf && sock->outbuf->len > 0) {
-       /* Couldn't send all data, put the queue back up, we'll send
-          rest later. */
-       SILC_LOG_DEBUG(("Could not purge immediately, sending rest later"));
-       SILC_SET_CONNECTION_FOR_OUTPUT(server->schedule, sock->sock);
-       SILC_SET_OUTBUF_PENDING(sock);
-       return;
-      }
-    } else if (ret == -1) {
-      SILC_LOG_ERROR(("Error purging packet queue, packets dropped"));
-    }
-
-    /* Purged all data */
-    SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
-    SILC_UNSET_OUTBUF_PENDING(sock);
-    silc_buffer_clear(sock->outbuf);
-  }
-}
-
 /* Send packet to clients that are known to be operators.  If server
    is router and `route' is TRUE then the packet would go to all operators
    in the SILC network.  If `route' is FALSE then only local operators
@@ -2105,18 +1558,18 @@ void silc_server_packet_queue_purge(SilcServer server,
 void silc_server_send_opers(SilcServer server,
                            SilcPacketType type,
                            SilcPacketFlags flags,
-                           bool route, bool local,
+                           SilcBool route, bool local,
                            unsigned char *data,
-                           SilcUInt32 data_len,
-                           bool force_send)
+                           SilcUInt32 data_len)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry client = NULL;
-  SilcSocketConnection sock;
+  SilcIDListData idata;
+  SilcPacketStream sock;
   SilcServerEntry *routed = NULL;
   SilcUInt32 routed_count = 0;
-  bool gone = FALSE;
+  SilcBool gone = FALSE;
   int k;
 
   SILC_LOG_DEBUG(("Sending %s packet to operators",
@@ -2124,10 +1577,10 @@ void silc_server_send_opers(SilcServer server,
 
   /* If local was requested send only locally connected operators. */
   if (local || (server->server_type == SILC_SERVER && !route)) {
-    if (!silc_idcache_get_all(server->local_list->clients, &list) ||
-       !silc_idcache_list_first(list, &id_cache))
+    if (!silc_idcache_get_all(server->local_list->clients, &list))
       return;
-    while (id_cache) {
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
       client = (SilcClientEntry)id_cache->context;
       if (!client->router && SILC_IS_LOCAL(client) &&
          (client->mode & SILC_UMODE_SERVER_OPERATOR ||
@@ -2136,24 +1589,20 @@ void silc_server_send_opers(SilcServer server,
        /* Send the packet to locally connected operator */
        silc_server_packet_send_dest(server, client->connection, type, flags,
                                     client->id, SILC_ID_CLIENT,
-                                    data, data_len, force_send);
+                                    data, data_len);
       }
-
-      if (!silc_idcache_list_next(list, &id_cache))
-       break;
     }
-    silc_idcache_list_free(list);
     return;
   }
 
-  if (!silc_idcache_get_all(server->local_list->clients, &list) ||
-      !silc_idcache_list_first(list, &id_cache))
+  if (!silc_idcache_get_all(server->local_list->clients, &list))
     return;
-  while (id_cache) {
+  silc_list_start(list);
+  while ((id_cache = silc_list_get(list))) {
     client = (SilcClientEntry)id_cache->context;
     if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
        !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
-      goto next;
+      continue;
 
     if (server->server_type != SILC_SERVER && client->router &&
        ((!route && client->router->router == server->id_entry) || route)) {
@@ -2163,50 +1612,47 @@ void silc_server_send_opers(SilcServer server,
        if (routed[k] == client->router)
          break;
       if (k < routed_count)
-       goto next;
+       continue;
 
       /* Route only once to router */
-      sock = (SilcSocketConnection)client->router->connection;
-      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      sock = client->router->connection;
+      idata = silc_packet_get_context(sock);
+      if (idata->conn_type == SILC_CONN_ROUTER) {
        if (gone)
-         goto next;
+         continue;
        gone = TRUE;
       }
 
       /* Send the packet */
       silc_server_packet_send_dest(server, sock, type, flags,
                                   client->id, SILC_ID_CLIENT,
-                                  data, data_len, force_send);
+                                  data, data_len);
 
       /* Mark this route routed already */
       routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
       routed[routed_count++] = client->router;
-      goto next;
+      continue;
     }
 
     if (client->router || !client->connection)
-      goto next;
+      continue;
 
     /* Send to locally connected client */
-    sock = (SilcSocketConnection)client->connection;
+    sock = client->connection;
     silc_server_packet_send_dest(server, sock, type, flags,
                                 client->id, SILC_ID_CLIENT,
-                                data, data_len, force_send);
+                                data, data_len);
 
-  next:
-    if (!silc_idcache_list_next(list, &id_cache))
-      break;
   }
-  silc_idcache_list_free(list);
 
-  if (!silc_idcache_get_all(server->global_list->clients, &list) ||
-      !silc_idcache_list_first(list, &id_cache))
+  if (!silc_idcache_get_all(server->global_list->clients, &list))
     return;
-  while (id_cache) {
+  silc_list_start(list);
+  while ((id_cache = silc_list_get(list))) {
     client = (SilcClientEntry)id_cache->context;
     if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
        !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
-      goto nextg;
+      continue;
 
     if (server->server_type != SILC_SERVER && client->router &&
        ((!route && client->router->router == server->id_entry) || route)) {
@@ -2216,49 +1662,45 @@ void silc_server_send_opers(SilcServer server,
        if (routed[k] == client->router)
          break;
       if (k < routed_count)
-       goto nextg;
+       continue;
 
       /* Route only once to router */
-      sock = (SilcSocketConnection)client->router->connection;
-      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      sock = client->router->connection;
+      idata = silc_packet_get_context(sock);
+      if (idata->conn_type == SILC_CONN_ROUTER) {
        if (gone)
-         goto nextg;
+         continue;
        gone = TRUE;
       }
 
       /* Send the packet */
       silc_server_packet_send_dest(server, sock, type, flags,
                                   client->id, SILC_ID_CLIENT,
-                                  data, data_len, force_send);
+                                  data, data_len);
 
       /* Mark this route routed already */
       routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
       routed[routed_count++] = client->router;
-      goto nextg;
+      continue;
     }
 
     if (client->router || !client->connection)
-      goto nextg;
+      continue;
 
     /* Send to locally connected client */
-    sock = (SilcSocketConnection)client->connection;
+    sock = client->connection;
     silc_server_packet_send_dest(server, sock, type, flags,
                                 client->id, SILC_ID_CLIENT,
-                                data, data_len, force_send);
-
-  nextg:
-    if (!silc_idcache_list_next(list, &id_cache))
-      break;
+                                data, data_len);
   }
-  silc_idcache_list_free(list);
   silc_free(routed);
 }
 
 /* Send a notify packet to operators */
 
 void silc_server_send_opers_notify(SilcServer server,
-                                  bool route,
-                                  bool local,
+                                  SilcBool route,
+                                  SilcBool local,
                                   SilcNotifyType type,
                                   SilcUInt32 argc, ...)
 {
@@ -2268,8 +1710,7 @@ void silc_server_send_opers_notify(SilcServer server,
   va_start(ap, argc);
   packet = silc_notify_payload_encode(type, argc, ap);
   silc_server_send_opers(server, SILC_PACKET_NOTIFY, 0,
-                        route, local, packet->data, packet->len,
-                        FALSE);
+                        route, local, packet->data, silc_buffer_len(packet));
   silc_buffer_free(packet);
   va_end(ap);
 }
index 2b0681b6012079463602f9fa9fbecc270878b880..bb5a18e8214ae08f5673cccea70a370acc1e0073 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2004 Pekka Riikonen
+  Copyright (C) 1997 - 2004, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 
 /* Prototypes */
 
-int silc_server_packet_send_real(SilcServer server,
-                                SilcSocketConnection sock,
-                                bool force_send);
-void silc_server_packet_send(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketType type,
-                            SilcPacketFlags flags,
-                            unsigned char *data,
-                            SilcUInt32 data_len,
-                            bool force_send);
-void silc_server_packet_send_dest(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketType type,
-                                 SilcPacketFlags flags,
-                                 void *dst_id,
-                                 SilcIdType dst_id_type,
-                                 unsigned char *data,
-                                 SilcUInt32 data_len,
-                                 bool force_send);
-void silc_server_packet_send_srcdest(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    SilcPacketType type,
-                                    SilcPacketFlags flags,
-                                    void *src_id,
-                                    SilcIdType src_id_type,
-                                    void *dst_id,
-                                    SilcIdType dst_id_type,
-                                    unsigned char *data,
-                                    SilcUInt32 data_len,
-                                    bool force_send);
-void silc_server_packet_broadcast(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 SilcPacketContext *packet);
-void silc_server_packet_route(SilcServer server,
-                             SilcSocketConnection sock,
-                             SilcPacketContext *packet);
+SilcBool silc_server_packet_send(SilcServer server,
+                                SilcPacketStream sock,
+                                SilcPacketType type,
+                                SilcPacketFlags flags,
+                                unsigned char *data,
+                                SilcUInt32 data_len);
+SilcBool silc_server_packet_send_dest(SilcServer server,
+                                     SilcPacketStream sock,
+                                     SilcPacketType type,
+                                     SilcPacketFlags flags,
+                                     void *dst_id,
+                                     SilcIdType dst_id_type,
+                                     unsigned char *data,
+                                     SilcUInt32 data_len);
+SilcBool silc_server_packet_send_srcdest(SilcServer server,
+                                        SilcPacketStream sock,
+                                        SilcPacketType type,
+                                        SilcPacketFlags flags,
+                                        void *src_id,
+                                        SilcIdType src_id_type,
+                                        void *dst_id,
+                                        SilcIdType dst_id_type,
+                                        unsigned char *data,
+                                        SilcUInt32 data_len);
+SilcBool silc_server_packet_broadcast(SilcServer server,
+                                     SilcPacketStream sock,
+                                     SilcPacket packet);
+SilcBool silc_server_packet_route(SilcServer server,
+                                 SilcPacketStream sock,
+                                 SilcPacket packet);
 void silc_server_packet_send_clients(SilcServer server,
                                     SilcHashTable clients,
                                     SilcPacketType type,
                                     SilcPacketFlags flags,
-                                    bool route,
+                                    SilcBool route,
                                     unsigned char *data,
-                                    SilcUInt32 data_len,
-                                    bool force_send);
+                                    SilcUInt32 data_len);
 void silc_server_packet_send_to_channel(SilcServer server,
-                                       SilcSocketConnection sender,
+                                       SilcPacketStream sender,
                                        SilcChannelEntry channel,
                                        SilcPacketType type,
-                                       bool route,
-                                       bool send_to_clients,
+                                       SilcBool route,
+                                       SilcBool send_to_clients,
                                        unsigned char *data,
-                                       SilcUInt32 data_len,
-                                       bool force_send);
+                                       SilcUInt32 data_len);
 void silc_server_packet_relay_to_channel(SilcServer server,
-                                        SilcSocketConnection sender_sock,
+                                        SilcPacketStream sender_sock,
                                         SilcChannelEntry channel,
                                         void *sender_id,
                                         SilcIdType sender_type,
                                         SilcClientEntry sender_entry,
                                         unsigned char *data,
-                                        SilcUInt32 data_len,
-                                        bool force_send);
+                                        SilcUInt32 data_len);
 void silc_server_packet_send_local_channel(SilcServer server,
                                           SilcChannelEntry channel,
                                           SilcPacketType type,
                                           SilcPacketFlags flags,
                                           unsigned char *data,
-                                          SilcUInt32 data_len,
-                                          bool force_send);
-void silc_server_send_private_message(SilcServer server,
-                                     SilcSocketConnection dst_sock,
-                                     SilcCipher cipher,
-                                     SilcHmac hmac,
-                                     SilcUInt32 sequence,
-                                     SilcPacketContext *packet);
+                                          SilcUInt32 data_len);
 void silc_server_send_motd(SilcServer server,
-                          SilcSocketConnection sock);
+                          SilcPacketStream sock);
 void silc_server_send_error(SilcServer server,
-                           SilcSocketConnection sock,
+                           SilcPacketStream sock,
                            const char *fmt, ...);
 void silc_server_send_notify(SilcServer server,
-                            SilcSocketConnection sock,
-                            bool broadcast,
+                            SilcPacketStream sock,
+                            SilcBool broadcast,
                             SilcNotifyType type,
                             SilcUInt32 argc, ...);
 void silc_server_send_notify_args(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  SilcNotifyType type,
                                  SilcUInt32 argc,
                                  SilcBuffer args);
 void silc_server_send_notify_channel_change(SilcServer server,
-                                           SilcSocketConnection sock,
-                                           bool broadcast,
+                                           SilcPacketStream sock,
+                                           SilcBool broadcast,
                                            SilcChannelID *old_id,
                                            SilcChannelID *new_id);
 void silc_server_send_notify_nick_change(SilcServer server,
-                                        SilcSocketConnection sock,
-                                        bool broadcast,
+                                        SilcPacketStream sock,
+                                        SilcBool broadcast,
                                         SilcClientID *old_id,
                                         SilcClientID *new_id,
                                         const char *nickname);
 void silc_server_send_notify_join(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  SilcChannelEntry channel,
                                  SilcClientID *client_id);
 void silc_server_send_notify_leave(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  bool broadcast,
+                                  SilcPacketStream sock,
+                                  SilcBool broadcast,
                                   SilcChannelEntry channel,
                                   SilcClientID *client_id);
 void silc_server_send_notify_cmode(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  bool broadcast,
+                                  SilcPacketStream sock,
+                                  SilcBool broadcast,
                                   SilcChannelEntry channel,
                                   SilcUInt32 mode_mask,
                                   void *id, SilcIdType id_type,
@@ -145,74 +129,74 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   SilcPublicKey founder_key,
                                   SilcBuffer channel_pubkeys);
 void silc_server_send_notify_cumode(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcChannelEntry channel,
                                    SilcUInt32 mode_mask,
                                    void *id, SilcIdType id_type,
                                    SilcClientID *target,
                                    SilcPublicKey founder_key);
 void silc_server_send_notify_signoff(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    bool broadcast,
+                                    SilcPacketStream sock,
+                                    SilcBool broadcast,
                                     SilcClientID *client_id,
                                     const char *message);
 void silc_server_send_notify_topic_set(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      bool broadcast,
+                                      SilcPacketStream sock,
+                                      SilcBool broadcast,
                                       SilcChannelEntry channel,
                                       void *id, SilcIdType id_type,
                                       char *topic);
 void silc_server_send_notify_kicked(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcChannelEntry channel,
                                    SilcClientID *client_id,
                                    SilcClientID *kicker,
                                    char *comment);
 void silc_server_send_notify_killed(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcClientID *client_id,
                                    const char *comment,
                                    void *killer, SilcIdType killer_type);
 void silc_server_send_notify_umode(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  bool broadcast,
+                                  SilcPacketStream sock,
+                                  SilcBool broadcast,
                                   SilcClientID *client_id,
                                   SilcUInt32 mode_mask);
 void silc_server_send_notify_ban(SilcServer server,
-                                SilcSocketConnection sock,
-                                bool broadcast,
+                                SilcPacketStream sock,
+                                SilcBool broadcast,
                                 SilcChannelEntry channel,
                                 unsigned char *action,
                                 SilcBuffer list);
 void silc_server_send_notify_invite(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   bool broadcast,
+                                   SilcPacketStream sock,
+                                   SilcBool broadcast,
                                    SilcChannelEntry channel,
                                    SilcClientID *client_id,
                                    unsigned char *action,
                                    SilcBuffer list);
 void silc_server_send_notify_watch(SilcServer server,
-                                  SilcSocketConnection sock,
+                                  SilcPacketStream sock,
                                   SilcClientEntry watcher,
                                   SilcClientEntry client,
                                   const char *nickname,
                                   SilcNotifyType type,
                                   SilcPublicKey public_key);
 void silc_server_send_notify_dest(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  void *dest_id,
                                  SilcIdType dest_id_type,
                                  SilcNotifyType type,
                                  SilcUInt32 argc, ...);
 void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcSocketConnection sender,
+                                       SilcPacketStream sender,
                                        SilcChannelEntry channel,
-                                       bool route_notify,
-                                       bool send_to_clients,
+                                       SilcBool route_notify,
+                                       SilcBool send_to_clients,
                                        SilcNotifyType type,
                                        SilcUInt32 argc, ...);
 void silc_server_send_notify_on_channels(SilcServer server,
@@ -221,35 +205,35 @@ void silc_server_send_notify_on_channels(SilcServer server,
                                         SilcNotifyType type,
                                         SilcUInt32 argc, ...);
 void silc_server_send_new_id(SilcServer server,
-                            SilcSocketConnection sock,
-                            bool broadcast,
+                            SilcPacketStream sock,
+                            SilcBool broadcast,
                             void *id, SilcIdType id_type,
                             SilcUInt32 id_len);
 void silc_server_send_new_channel(SilcServer server,
-                                 SilcSocketConnection sock,
-                                 bool broadcast,
+                                 SilcPacketStream sock,
+                                 SilcBool broadcast,
                                  char *channel_name,
                                  void *channel_id,
                                  SilcUInt32 channel_id_len,
                                  SilcUInt32 mode);
 void silc_server_send_channel_key(SilcServer server,
-                                 SilcSocketConnection sender,
+                                 SilcPacketStream sender,
                                  SilcChannelEntry channel,
                                  unsigned char route);
 void silc_server_send_command(SilcServer server,
-                             SilcSocketConnection sock,
+                             SilcPacketStream sock,
                              SilcCommand command,
                              SilcUInt16 ident,
                              SilcUInt32 argc, ...);
 void silc_server_send_command_reply(SilcServer server,
-                                   SilcSocketConnection sock,
+                                   SilcPacketStream sock,
                                    SilcCommand command,
                                    SilcStatus status,
                                    SilcStatus error,
                                    SilcUInt16 ident,
                                    SilcUInt32 argc, ...);
 void silc_server_send_dest_command_reply(SilcServer server,
-                                        SilcSocketConnection sock,
+                                        SilcPacketStream sock,
                                         void *dst_id,
                                         SilcIdType dst_id_type,
                                         SilcCommand command,
@@ -257,31 +241,25 @@ void silc_server_send_dest_command_reply(SilcServer server,
                                         SilcStatus error,
                                         SilcUInt16 ident,
                                         SilcUInt32 argc, ...);
-void silc_server_send_heartbeat(SilcServer server,
-                               SilcSocketConnection sock);
 void silc_server_relay_packet(SilcServer server,
-                             SilcSocketConnection dst_sock,
+                             SilcPacketStream dst_sock,
                              SilcCipher cipher,
                              SilcHmac hmac,
                              SilcUInt32 sequence,
-                             SilcPacketContext *packet,
-                             bool force_send);
+                             SilcPacket *packet);
 void silc_server_send_connection_auth_request(SilcServer server,
-                                             SilcSocketConnection sock,
+                                             SilcPacketStream sock,
                                              SilcUInt16 conn_type,
                                              SilcAuthMethod auth_meth);
-void silc_server_packet_queue_purge(SilcServer server,
-                                   SilcSocketConnection sock);
 void silc_server_send_opers(SilcServer server,
                            SilcPacketType type,
                            SilcPacketFlags flags,
-                           bool route, bool local,
+                           SilcBool route, bool local,
                            unsigned char *data,
-                           SilcUInt32 data_len,
-                           bool force_send);
+                           SilcUInt32 data_len);
 void silc_server_send_opers_notify(SilcServer server,
-                                  bool route,
-                                  bool local,
+                                  SilcBool route,
+                                  SilcBool local,
                                   SilcNotifyType type,
                                   SilcUInt32 argc, ...);
 
diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c
deleted file mode 100644 (file)
index 20525e5..0000000
+++ /dev/null
@@ -1,1722 +0,0 @@
-/*
-
-  protocol.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 1997 - 2003 Pekka Riikonen
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-*/
-/*
- * Server side of the protocols.
- */
-/* $Id$ */
-
-#include "serverincludes.h"
-#include "server_internal.h"
-
-SILC_TASK_CALLBACK(silc_server_protocol_connection_auth);
-SILC_TASK_CALLBACK(silc_server_protocol_key_exchange);
-SILC_TASK_CALLBACK(silc_server_protocol_rekey);
-
-/*
- * Key Exhange protocol functions
- */
-
-static bool
-silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
-                               SilcSocketType conn_type,
-                               unsigned char *pk, SilcUInt32 pk_len,
-                               SilcSKEPKType pk_type)
-{
-  char file[256], filename[256], *fingerprint;
-  struct stat st;
-
-  if (pk_type != SILC_SKE_PK_TYPE_SILC) {
-    SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d",
-                     sock->hostname, sock->ip, sock->port, pk_type));
-    return FALSE;
-  }
-
-  /* Accept client keys without verification */
-  if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
-    SILC_LOG_DEBUG(("Accepting client public key without verification"));
-    return TRUE;
-  }
-
-  /* XXX For now, accept server keys without verification too. We are
-     currently always doing mutual authentication so the proof of posession
-     of the private key is verified, and if server is authenticated in
-     conn auth protocol with public key we MUST have the key already. */
-  return TRUE;
-  /* Rest is unreachable code! */
-
-  memset(filename, 0, sizeof(filename));
-  memset(file, 0, sizeof(file));
-  snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", sock->hostname,
-          sock->port);
-  snprintf(filename, sizeof(filename) - 1, SILC_ETCDIR "/serverkeys/%s",
-          file);
-
-  /* Create serverkeys directory if it doesn't exist. */
-  if (stat(SILC_ETCDIR "/serverkeys", &st) < 0) {
-    /* If dir doesn't exist */
-    if (errno == ENOENT) {
-      if (mkdir(SILC_ETCDIR "/serverkeys", 0755) < 0) {
-       SILC_LOG_ERROR(("Couldn't create `%s' directory\n",
-                       SILC_ETCDIR "/serverkeys"));
-       return TRUE;
-      }
-    } else {
-      SILC_LOG_ERROR(("%s\n", strerror(errno)));
-      return TRUE;
-    }
-  }
-
-  /* Take fingerprint of the public key */
-  fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
-  SILC_LOG_DEBUG(("Received server %s (%s) port %d public key (%s)",
-                 sock->hostname, sock->ip, sock->port, fingerprint));
-  silc_free(fingerprint);
-
-  /* Check whether this key already exists */
-  if (stat(filename, &st) < 0) {
-    /* We don't have it, then cache it. */
-    SILC_LOG_DEBUG(("New public key from server"));
-
-    silc_pkcs_save_public_key_data(filename, pk, pk_len,
-                                  SILC_PKCS_FILE_PEM);
-    return TRUE;
-  } else {
-    /* The key already exists, verify it. */
-    SilcPublicKey public_key;
-    unsigned char *encpk;
-    SilcUInt32 encpk_len;
-
-    SILC_LOG_DEBUG(("We have the public key saved locally"));
-
-    /* Load the key file */
-    if (!silc_pkcs_load_public_key(filename, &public_key,
-                                  SILC_PKCS_FILE_PEM))
-      if (!silc_pkcs_load_public_key(filename, &public_key,
-                                    SILC_PKCS_FILE_BIN)) {
-       SILC_LOG_WARNING(("Could not load local copy of the %s (%s) port %d "
-                         "server public key", sock->hostname, sock->ip,
-                         sock->port));
-
-       /* Save the key for future checking */
-       unlink(filename);
-       silc_pkcs_save_public_key_data(filename, pk, pk_len,
-                                      SILC_PKCS_FILE_PEM);
-       return TRUE;
-      }
-
-    /* Encode the key data */
-    encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
-    if (!encpk) {
-      SILC_LOG_WARNING(("Local copy of the server %s (%s) port %d public key "
-                       "is malformed", sock->hostname, sock->ip, sock->port));
-
-      /* Save the key for future checking */
-      unlink(filename);
-      silc_pkcs_save_public_key_data(filename, pk, pk_len, SILC_PKCS_FILE_PEM);
-      return TRUE;
-    }
-
-    if (memcmp(pk, encpk, encpk_len)) {
-      SILC_LOG_WARNING(("%s (%s) port %d server public key does not match "
-                       "with local copy", sock->hostname, sock->ip,
-                       sock->port));
-      SILC_LOG_WARNING(("It is possible that the key has expired or changed"));
-      SILC_LOG_WARNING(("It is also possible that some one is performing "
-                       "man-in-the-middle attack"));
-      SILC_LOG_WARNING(("Will not accept the server %s (%s) port %d public "
-                       "key",
-                       sock->hostname, sock->ip, sock->port));
-      return FALSE;
-    }
-
-    /* Local copy matched */
-    return TRUE;
-  }
-}
-
-/* Callback that is called when we have received KE2 payload from
-   responder. We try to verify the public key now. */
-
-static void
-silc_server_protocol_ke_verify_key(SilcSKE ske,
-                                  unsigned char *pk_data,
-                                  SilcUInt32 pk_len,
-                                  SilcSKEPKType pk_type,
-                                  void *context,
-                                  SilcSKEVerifyCbCompletion completion,
-                                  void *completion_context)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx =
-    (SilcServerKEInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-
-  SILC_LOG_DEBUG(("Verifying received public key"));
-
-  if (silc_verify_public_key_internal(
-                 server, ctx->sock,
-                 (ctx->responder == FALSE ?
-                  SILC_SOCKET_TYPE_ROUTER:
-                  ctx->sconfig.ref_ptr ? SILC_SOCKET_TYPE_SERVER :
-                  ctx->rconfig.ref_ptr ? SILC_SOCKET_TYPE_ROUTER :
-                  SILC_SOCKET_TYPE_CLIENT),
-                 pk_data, pk_len, pk_type))
-    completion(ske, SILC_SKE_STATUS_OK, completion_context);
-  else
-    completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
-              completion_context);
-}
-
-/* Packet sending callback. This function is provided as packet sending
-   routine to the Key Exchange functions. */
-
-static void silc_server_protocol_ke_send_packet(SilcSKE ske,
-                                               SilcBuffer packet,
-                                               SilcPacketType type,
-                                               void *context)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx =
-    (SilcServerKEInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-
-  /* Send the packet immediately */
-  silc_server_packet_send(server, ske->sock,
-                         type, 0, packet->data, packet->len, TRUE);
-}
-
-/* Sets the negotiated key material into use for particular connection. */
-
-int silc_server_protocol_ke_set_keys(SilcServer server,
-                                    SilcSKE ske,
-                                    SilcSocketConnection sock,
-                                    SilcSKEKeyMaterial *keymat,
-                                    SilcCipher cipher,
-                                    SilcPKCS pkcs,
-                                    SilcHash hash,
-                                    SilcHmac hmac,
-                                    SilcSKEDiffieHellmanGroup group,
-                                    bool is_responder)
-{
-  SilcUnknownEntry conn_data;
-  SilcIDListData idata;
-  const char *cname = silc_cipher_get_name(cipher);
-
-  SILC_LOG_DEBUG(("Setting new keys into use"));
-
-  conn_data = silc_calloc(1, sizeof(*conn_data));
-  idata = (SilcIDListData)conn_data;
-
-  /* Allocate cipher to be used in the communication */
-  if (!silc_cipher_alloc((char *)cname, &idata->send_key)) {
-    silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s", cname));
-    return FALSE;
-  }
-  if (!silc_cipher_alloc((char *)cname, &idata->receive_key)) {
-    silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s", cname));
-    return FALSE;
-  }
-
-  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
-                      &idata->hmac_send)) {
-    silc_cipher_free(idata->send_key);
-    silc_cipher_free(idata->receive_key);
-    silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s",
-                   silc_hmac_get_name(hmac)));
-    return FALSE;
-  }
-
-  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
-                      &idata->hmac_receive)) {
-    silc_cipher_free(idata->send_key);
-    silc_cipher_free(idata->receive_key);
-    silc_hmac_free(idata->hmac_send);
-    silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s",
-                   silc_hmac_get_name(hmac)));
-    return FALSE;
-  }
-
-  if (is_responder == TRUE) {
-    silc_cipher_set_key(idata->send_key, keymat->receive_enc_key,
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
-    silc_cipher_set_key(idata->receive_key, keymat->send_enc_key,
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
-    silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key,
-                     keymat->hmac_key_len);
-    silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key,
-                     keymat->hmac_key_len);
-  } else {
-    silc_cipher_set_key(idata->send_key, keymat->send_enc_key,
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->send_key, keymat->send_iv);
-    silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key,
-                       keymat->enc_key_len);
-    silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
-    silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key,
-                     keymat->hmac_key_len);
-    silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key,
-                     keymat->hmac_key_len);
-  }
-
-  idata->rekey = silc_calloc(1, sizeof(*idata->rekey));
-  idata->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
-                                          keymat->enc_key_len / 8);
-  idata->rekey->enc_key_len = keymat->enc_key_len / 8;
-
-  if (ske->prop->flags & SILC_SKE_SP_FLAG_PFS)
-    idata->rekey->pfs = TRUE;
-  idata->rekey->ske_group = silc_ske_group_get_number(group);
-
-  /* Save the hash */
-  if (!silc_hash_alloc(silc_hash_get_name(hash), &idata->hash)) {
-    silc_cipher_free(idata->send_key);
-    silc_cipher_free(idata->receive_key);
-    silc_hmac_free(idata->hmac_send);
-    silc_hmac_free(idata->hmac_receive);
-    silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s",
-                   silc_hash_get_name(hash)));
-    return FALSE;
-  }
-
-  /* Save the remote host's public key */
-  silc_pkcs_public_key_decode(ske->ke1_payload->pk_data,
-                             ske->ke1_payload->pk_len, &idata->public_key);
-  if (ske->prop->flags & SILC_SKE_SP_FLAG_MUTUAL)
-    silc_hash_make(server->sha1hash, ske->ke1_payload->pk_data,
-                  ske->ke1_payload->pk_len, idata->fingerprint);
-
-  sock->user_data = (void *)conn_data;
-
-  SILC_LOG_INFO(("%s (%s) security properties: %s %s %s %s",
-                sock->hostname, sock->ip,
-                silc_cipher_get_name(idata->send_key),
-                (char *)silc_hmac_get_name(idata->hmac_send),
-                silc_hash_get_name(idata->hash),
-                ske->prop->flags & SILC_SKE_SP_FLAG_PFS ? "PFS" : ""));
-
-  return TRUE;
-}
-
-/* Check remote host version string */
-
-SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
-                                    SilcUInt32 len, void *context)
-{
-  SilcUInt32 l_protocol_version = 0, r_protocol_version = 0;
-
-  SILC_LOG_INFO(("%s (%s) is version %s", ske->sock->hostname,
-                ske->sock->ip, version));
-
-  if (!silc_parse_version_string(version, &r_protocol_version, NULL, NULL,
-                                NULL, NULL)) {
-    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
-                   ske->sock->hostname, ske->sock->ip, version));
-    return SILC_SKE_STATUS_BAD_VERSION;
-  }
-
-  if (!silc_parse_version_string(silc_version_string,
-                                &l_protocol_version, NULL, NULL,
-                                NULL, NULL)) {
-    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
-                   ske->sock->hostname, ske->sock->ip, version));
-    return SILC_SKE_STATUS_BAD_VERSION;
-  }
-
-  /* If remote is too new, don't connect */
-  if (l_protocol_version < r_protocol_version) {
-    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
-                   ske->sock->hostname, ske->sock->ip, version));
-    return SILC_SKE_STATUS_BAD_VERSION;
-  }
-
-  ske->sock->version = r_protocol_version;
-
-  return SILC_SKE_STATUS_OK;
-}
-
-/* Callback that is called by the SKE to indicate that it is safe to
-   continue the execution of the protocol. This is used only if we are
-   initiator.  Is given as argument to the silc_ske_initiator_finish or
-   silc_ske_responder_phase_2 functions. This is called due to the fact
-   that the public key verification process is asynchronous and we must
-   not continue the protocl until the public key has been verified and
-   this callback is called. */
-
-static void silc_server_protocol_ke_continue(SilcSKE ske, void *context)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx =
-    (SilcServerKEInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-
-  if (ske->status != SILC_SKE_STATUS_OK) {
-    SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                   silc_ske_map_status(ske->status), ctx->sock->hostname,
-                   ctx->sock->ip));
-
-    protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute(protocol, server->schedule, 0, 300000);
-    return;
-  }
-
-  /* Send Ok to the other end. We will end the protocol as responder
-     sends Ok to us when we will take the new keys into use. */
-  if (ctx->responder == FALSE) {
-    SILC_LOG_DEBUG(("Ending key exchange protocol"));
-    silc_ske_end(ctx->ske);
-
-    /* End the protocol on the next round */
-    protocol->state = SILC_PROTOCOL_STATE_END;
-  }
-
-  /* Advance protocol state and call the next state if we are responder.
-     This happens when this callback was sent to silc_ske_responder_phase_2
-     function. */
-  if (ctx->responder == TRUE) {
-    protocol->state++;
-    silc_protocol_execute(protocol, server->schedule, 0, 100000);
-  }
-}
-
-/* Performs key exchange protocol. This is used for both initiator
-   and responder key exchange. This is performed always when accepting
-   new connection to the server. This may be called recursively. */
-
-SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx =
-    (SilcServerKEInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
-
-  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
-    protocol->state = SILC_PROTOCOL_STATE_START;
-
-  SILC_LOG_DEBUG(("Current protocol state %d", protocol->state));
-
-  switch(protocol->state) {
-  case SILC_PROTOCOL_STATE_START:
-    {
-      /*
-       * Start protocol
-       */
-      SilcSKE ske;
-
-      /* Allocate Key Exchange object */
-      ctx->ske = ske = silc_ske_alloc(server->rng, server);
-
-      silc_ske_set_callbacks(ske, silc_server_protocol_ke_send_packet, NULL,
-                            silc_server_protocol_ke_verify_key,
-                            silc_server_protocol_ke_continue,
-                            silc_ske_check_version, context);
-
-      if (ctx->responder == TRUE) {
-       if (!ctx->packet) {
-         SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                         silc_ske_map_status(status), ctx->sock->hostname,
-                         ctx->sock->ip));
-
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       /* Start the key exchange by processing the received security
-          properties packet from initiator. */
-       SILC_LOG_DEBUG(("Process security property list (KE)"));
-       status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
-                                         silc_version_string,
-                                         ctx->packet->buffer, ctx->flags);
-      } else {
-       SilcSKEStartPayload *start_payload;
-
-       SILC_LOG_DEBUG(("Send security property list (KE)"));
-
-       /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, ctx->flags,
-                                             silc_version_string,
-                                             &start_payload);
-
-       /* Start the key exchange by sending our security properties
-          to the remote end. */
-       status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
-                                         start_payload);
-      }
-
-      /* Return now if the procedure is pending. */
-      if (status == SILC_SKE_STATUS_PENDING)
-       return;
-
-      if (status != SILC_SKE_STATUS_OK) {
-       SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                       silc_ske_map_status(status), ctx->sock->hostname,
-                       ctx->sock->ip));
-
-       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->schedule, 0, 300000);
-       return;
-      }
-
-      /* Advance protocol state and call the next state if we are responder */
-      protocol->state++;
-      if (ctx->responder == TRUE)
-       silc_protocol_execute(protocol, server->schedule, 0, 100000);
-    }
-    break;
-  case 2:
-    {
-      /*
-       * Phase 1
-       */
-      if (ctx->responder == TRUE) {
-       /* Sends the selected security properties to the initiator. */
-       SILC_LOG_DEBUG(("Send security property list reply (KE)"));
-       status = silc_ske_responder_phase_1(ctx->ske);
-      } else {
-       if (!ctx->packet) {
-         SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                         silc_ske_map_status(status), ctx->sock->hostname,
-                         ctx->sock->ip));
-
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       /* Call Phase-1 function. This processes the Key Exchange Start
-          paylaod reply we just got from the responder. The callback
-          function will receive the processed payload where we will
-          save it. */
-       SILC_LOG_DEBUG(("Process security property list reply (KE)"));
-       status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet->buffer);
-      }
-
-      /* Return now if the procedure is pending. */
-      if (status == SILC_SKE_STATUS_PENDING)
-       return;
-
-      if (status != SILC_SKE_STATUS_OK) {
-       SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                       silc_ske_map_status(status), ctx->sock->hostname,
-                       ctx->sock->ip));
-
-       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->schedule, 0, 300000);
-       return;
-      }
-
-      /* Advance protocol state and call next state if we are initiator */
-      protocol->state++;
-      if (ctx->responder == FALSE)
-       silc_protocol_execute(protocol, server->schedule, 0, 100000);
-    }
-    break;
-  case 3:
-    {
-      /*
-       * Phase 2
-       */
-      if (ctx->responder == TRUE) {
-       if (!ctx->packet) {
-         SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                         silc_ske_map_status(status), ctx->sock->hostname,
-                         ctx->sock->ip));
-
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       /* Process the received Key Exchange 1 Payload packet from
-          the initiator. This also creates our parts of the Diffie
-          Hellman algorithm. The silc_server_protocol_ke_continue
-          will be called after the public key has been verified. */
-       SILC_LOG_DEBUG(("Process KE1 packet"));
-       status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
-      } else {
-       /* Call the Phase-2 function. This creates Diffie Hellman
-          key exchange parameters and sends our public part inside
-          Key Exhange 1 Payload to the responder. */
-       SILC_LOG_DEBUG(("Send KE1 packet"));
-       status = silc_ske_initiator_phase_2(ctx->ske,
-                                           server->public_key,
-                                           server->private_key,
-                                           SILC_SKE_PK_TYPE_SILC);
-       protocol->state++;
-      }
-
-      /* Return now if the procedure is pending. */
-      if (status == SILC_SKE_STATUS_PENDING)
-       return;
-
-      if (status != SILC_SKE_STATUS_OK) {
-       SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                       silc_ske_map_status(status), ctx->sock->hostname,
-                       ctx->sock->ip));
-
-       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->schedule, 0, 300000);
-       return;
-      }
-    }
-    break;
-  case 4:
-    {
-      /*
-       * Finish protocol
-       */
-      if (ctx->responder == TRUE) {
-       /* This creates the key exchange material and sends our
-          public parts to the initiator inside Key Exchange 2 Payload. */
-       SILC_LOG_DEBUG(("Process KE2 packet"));
-       status = silc_ske_responder_finish(ctx->ske,
-                                          server->public_key,
-                                          server->private_key,
-                                          SILC_SKE_PK_TYPE_SILC);
-
-       /* End the protocol on the next round */
-       protocol->state = SILC_PROTOCOL_STATE_END;
-      } else {
-       if (!ctx->packet) {
-         SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                         silc_ske_map_status(status), ctx->sock->hostname,
-                         ctx->sock->ip));
-
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       /* Finish the protocol. This verifies the Key Exchange 2 payload
-          sent by responder. The silc_server_protocol_ke_continue will
-          be called after the public key has been verified. */
-       SILC_LOG_DEBUG(("Send KE2 packet"));
-       status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
-      }
-
-      /* Return now if the procedure is pending. */
-      if (status == SILC_SKE_STATUS_PENDING)
-       return;
-
-      if (status != SILC_SKE_STATUS_OK) {
-       SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
-                       silc_ske_map_status(status), ctx->sock->hostname,
-                       ctx->sock->ip));
-
-       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->schedule, 0, 300000);
-       return;
-      }
-    }
-    break;
-
-  case SILC_PROTOCOL_STATE_END:
-    {
-      /*
-       * End protocol
-       */
-      SilcSKEKeyMaterial *keymat;
-      int key_len = silc_cipher_get_key_len(ctx->ske->prop->cipher);
-      int hash_len = silc_hash_len(ctx->ske->prop->hash);
-
-      SILC_LOG_DEBUG(("Process computed key material"));
-
-      /* Process the key material */
-      keymat = silc_calloc(1, sizeof(*keymat));
-      status = silc_ske_process_key_material(ctx->ske, 16, key_len, hash_len,
-                                            keymat);
-      if (status != SILC_SKE_STATUS_OK) {
-       SILC_LOG_ERROR(("Error during Key Exchange protocol: "
-                       "could not process key material"));
-
-       protocol->state = SILC_PROTOCOL_STATE_ERROR;
-       silc_protocol_execute(protocol, server->schedule, 0, 300000);
-       silc_ske_free_key_material(keymat);
-       return;
-      }
-      ctx->keymat = keymat;
-
-      /* Send Ok to the other end if we are responder. If we are initiator
-        we have sent this already. */
-      if (ctx->responder == TRUE) {
-       SILC_LOG_DEBUG(("Ending key exchange protocol"));
-       silc_ske_end(ctx->ske);
-      }
-
-      /* Unregister the timeout task since the protocol has ended.
-        This was the timeout task to be executed if the protocol is
-        not completed fast enough. */
-      if (ctx->timeout_task)
-       silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
-      /* Assure that after calling final callback there cannot be pending
-        executions for this protocol anymore. This just unregisters any
-        timeout callbacks for this protocol. */
-      silc_protocol_cancel(protocol, server->schedule);
-
-      /* Call the final callback */
-      if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->schedule);
-      else
-       silc_protocol_free(protocol);
-    }
-    break;
-
-  case SILC_PROTOCOL_STATE_ERROR:
-    /*
-     * Error occured
-     */
-
-    /* Send abort notification */
-    silc_ske_abort(ctx->ske, ctx->ske->status);
-
-    /* Unregister the timeout task since the protocol has ended.
-       This was the timeout task to be executed if the protocol is
-       not completed fast enough. */
-    if (ctx->timeout_task)
-      silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
-    /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any
-       timeout callbacks for this protocol. */
-    silc_protocol_cancel(protocol, server->schedule);
-
-    /* On error the final callback is always called. */
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
-    break;
-
-  case SILC_PROTOCOL_STATE_FAILURE:
-    /*
-     * We have received failure from remote
-     */
-
-    /* Unregister the timeout task since the protocol has ended.
-       This was the timeout task to be executed if the protocol is
-       not completed fast enough. */
-    if (ctx->timeout_task)
-      silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
-    /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any
-       timeout callbacks for this protocol. */
-    silc_protocol_cancel(protocol, server->schedule);
-
-    /* On error the final callback is always called. */
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
-    break;
-
-  case SILC_PROTOCOL_STATE_UNKNOWN:
-    break;
-  }
-}
-
-/*
- * Connection Authentication protocol functions
- */
-
-static int
-silc_server_password_authentication(SilcServer server, char *local_auth,
-                                   char *remote_auth)
-{
-  if (!remote_auth || !local_auth || strlen(local_auth) != strlen(remote_auth))
-    return FALSE;
-
-  if (!memcmp(remote_auth, local_auth, strlen(local_auth)))
-    return TRUE;
-
-  return FALSE;
-}
-
-static int
-silc_server_public_key_authentication(SilcServer server,
-                                     SilcPublicKey pub_key,
-                                     unsigned char *sign,
-                                     SilcUInt32 sign_len,
-                                     SilcSKE ske)
-{
-  SilcPKCS pkcs;
-  int len;
-  SilcBuffer auth;
-
-  if (!pub_key || !sign)
-    return FALSE;
-
-  silc_pkcs_alloc(pub_key->name, &pkcs);
-  if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
-    silc_pkcs_free(pkcs);
-    return FALSE;
-  }
-
-  /* Make the authentication data. Protocol says it is HASH plus
-     KE Start Payload. */
-  len = ske->hash_len + ske->start_payload_copy->len;
-  auth = silc_buffer_alloc(len);
-  silc_buffer_pull_tail(auth, len);
-  silc_buffer_format(auth,
-                    SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
-                    SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
-                                         ske->start_payload_copy->len),
-                    SILC_STR_END);
-
-  /* Verify signature */
-  if (silc_pkcs_verify_with_hash(pkcs, ske->prop->hash, sign, sign_len,
-                                auth->data, auth->len)) {
-    silc_pkcs_free(pkcs);
-    silc_buffer_free(auth);
-    return TRUE;
-  }
-
-  silc_pkcs_free(pkcs);
-  silc_buffer_free(auth);
-  return FALSE;
-}
-
-static int
-silc_server_get_public_key_auth(SilcServer server,
-                               unsigned char **auth_data,
-                               SilcUInt32 *auth_data_len,
-                               SilcSKE ske)
-{
-  int len;
-  SilcPKCS pkcs;
-  SilcBuffer auth;
-
-  pkcs = server->pkcs;
-
-  /* Make the authentication data. Protocol says it is HASH plus
-     KE Start Payload. */
-  len = ske->hash_len + ske->start_payload_copy->len;
-  auth = silc_buffer_alloc(len);
-  silc_buffer_pull_tail(auth, len);
-  silc_buffer_format(auth,
-                    SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
-                    SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
-                                         ske->start_payload_copy->len),
-                    SILC_STR_END);
-
-  *auth_data = silc_calloc((silc_pkcs_get_key_len(pkcs) / 8) + 1,
-                          sizeof(**auth_data));
-  if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data,
-                              auth->len, *auth_data, auth_data_len)) {
-    silc_buffer_free(auth);
-    return TRUE;
-  }
-
-  SILC_LOG_ERROR(("Error computing signature"));
-
-  silc_free(*auth_data);
-  silc_buffer_free(auth);
-  return FALSE;
-}
-
-/* Function that actually performs the authentication to the remote. This
-   supports both passphrase and public key authentication. */
-
-static bool
-silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
-                              char *local_passphrase,
-                              SilcHashTable local_publickeys,
-                              unsigned char *remote_auth,
-                              SilcUInt32 remote_auth_len)
-{
-  SilcServer server = (SilcServer)ctx->server;
-  SilcSKE ske = ctx->ske;
-  bool result = FALSE;
-
-  /* If we don't have authentication data set at all we do not require
-     authentication at all */
-  if (!local_passphrase && (!local_publickeys ||
-                           !silc_hash_table_count(local_publickeys))) {
-    SILC_LOG_DEBUG(("No authentication required"));
-    return TRUE;
-  }
-
-  /* If both passphrase and public key is provided then we'll try both of
-     them and see which one of them authenticates.  If only one of them is
-     set, then try only that. */
-
-  /* Try first passphrase (as it is faster to check) */
-  if (local_passphrase) {
-    SILC_LOG_DEBUG(("Password authentication"));
-    result = silc_server_password_authentication(server, local_passphrase,
-                                                remote_auth);
-  }
-
-  /* Try public key authenetication */
-  if (!result && local_publickeys) {
-    SilcPublicKey cached_key;
-    SilcPublicKey remote_key =
-      ((SilcIDListData)ctx->sock->user_data)->public_key;
-
-    SILC_LOG_DEBUG(("Public key authentication"));
-
-    /* Find the public key to be used in authentication */
-    cached_key = silc_server_find_public_key(server, local_publickeys,
-                                            remote_key);
-    if (!cached_key)
-      return FALSE;
-
-    result = silc_server_public_key_authentication(server, cached_key,
-                                                  remote_auth,
-                                                  remote_auth_len, ske);
-  }
-
-  SILC_LOG_DEBUG(("Authentication %s", result ? "successful" : "failed"));
-
-  return result;
-}
-
-/* Performs connection authentication protocol. If responder, we
-   authenticate the remote data received. If initiator, we will send
-   authentication data to the remote end. */
-
-SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerConnAuthInternalContext *ctx =
-    (SilcServerConnAuthInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-
-  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
-    protocol->state = SILC_PROTOCOL_STATE_START;
-
-  SILC_LOG_DEBUG(("Current protocol state %d", protocol->state));
-
-  switch(protocol->state) {
-  case SILC_PROTOCOL_STATE_START:
-    {
-      /*
-       * Start protocol.
-       */
-
-      if (ctx->responder == TRUE) {
-       /*
-        * We are receiving party
-        */
-       int ret;
-       SilcUInt16 payload_len;
-       SilcUInt16 conn_type;
-       unsigned char *auth_data = NULL;
-
-       SILC_LOG_INFO(("Performing authentication protocol for %s (%s)",
-                      ctx->sock->hostname, ctx->sock->ip));
-
-       if (!ctx->packet) {
-         SILC_LOG_ERROR(("Bad authentication protocol request"));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       /* Parse the received authentication data packet. The received
-          payload is Connection Auth Payload. */
-       ret = silc_buffer_unformat(ctx->packet->buffer,
-                                  SILC_STR_UI_SHORT(&payload_len),
-                                  SILC_STR_UI_SHORT(&conn_type),
-                                  SILC_STR_END);
-       if (ret == -1) {
-         SILC_LOG_ERROR(("Bad payload in authentication packet"));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       if (payload_len != ctx->packet->buffer->len) {
-         SILC_LOG_ERROR(("Bad payload length in authentication packet"));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       payload_len -= 4;
-
-       if (conn_type < SILC_SOCKET_TYPE_CLIENT ||
-           conn_type > SILC_SOCKET_TYPE_ROUTER) {
-         SILC_LOG_ERROR(("Bad connection type (%d) in authentication packet",
-                         conn_type));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       if (payload_len > 0) {
-         /* Get authentication data */
-         silc_buffer_pull(ctx->packet->buffer, 4);
-         ret = silc_buffer_unformat(ctx->packet->buffer,
-                                    SILC_STR_UI_XNSTRING_ALLOC(&auth_data,
-                                                               payload_len),
-                                    SILC_STR_END);
-         if (ret == -1) {
-           SILC_LOG_DEBUG(("Bad payload in authentication payload"));
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 0, 300000);
-           return;
-         }
-       }
-
-       /*
-        * Check the remote connection type and make sure that we have
-        * configured this connection. If we haven't allowed this connection
-        * the authentication must be failed.
-        */
-
-       SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
-
-       /* Remote end is client */
-       if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
-         SilcServerConfigClient *client = ctx->cconfig.ref_ptr;
-
-         if (client) {
-           ret = silc_server_get_authentication(ctx, client->passphrase,
-                                                client->publickeys,
-                                                auth_data, payload_len);
-           if (!ret) {
-             /* Authentication failed */
-             SILC_LOG_ERROR(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 0, 300000);
-             return;
-           }
-         } else {
-           SILC_LOG_ERROR(("Remote client connection not configured"));
-           SILC_LOG_ERROR(("Authentication failed"));
-           silc_free(auth_data);
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule,
-                                 0, 300000);
-           return;
-         }
-       }
-
-       /* Remote end is server */
-       if (conn_type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerConfigServer *serv = ctx->sconfig.ref_ptr;
-
-         if (serv) {
-           ret = silc_server_get_authentication(ctx, serv->passphrase,
-                                                serv->publickeys,
-                                                auth_data, payload_len);
-           if (!ret) {
-             /* Authentication failed */
-             SILC_LOG_ERROR(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 0, 300000);
-             return;
-           }
-         } else {
-           SILC_LOG_ERROR(("Remote server connection not configured"));
-           SILC_LOG_ERROR(("Authentication failed"));
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule,
-                                 0, 300000);
-           silc_free(auth_data);
-           return;
-         }
-       }
-
-       /* Remote end is router */
-       if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
-         SilcServerConfigRouter *serv = ctx->rconfig.ref_ptr;
-
-         if (serv) {
-           ret = silc_server_get_authentication(ctx, serv->passphrase,
-                                                serv->publickeys,
-                                                auth_data, payload_len);
-           if (!ret) {
-             /* Authentication failed */
-             SILC_LOG_ERROR(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 0, 300000);
-             return;
-           }
-         } else {
-           SILC_LOG_ERROR(("Remote router connection not configured"));
-           SILC_LOG_ERROR(("Authentication failed"));
-           silc_free(auth_data);
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule,
-                                 0, 300000);
-           return;
-         }
-       }
-
-       silc_free(auth_data);
-
-       /* Save connection type. This is later used to create the
-          ID for the connection. */
-       ctx->conn_type = conn_type;
-
-       /* Advance protocol state. */
-       protocol->state = SILC_PROTOCOL_STATE_END;
-       silc_protocol_execute(protocol, server->schedule, 0, 0);
-
-      } else {
-       /*
-        * We are initiator. We are authenticating ourselves to a
-        * remote server. We will send the authentication data to the
-        * other end for verify.
-        */
-       SilcBuffer packet;
-       int payload_len = 0;
-       unsigned char *auth_data = NULL;
-       SilcUInt32 auth_data_len = 0;
-
-       switch(ctx->auth_meth) {
-       case SILC_AUTH_NONE:
-         /* No authentication required */
-         break;
-
-       case SILC_AUTH_PASSWORD:
-         /* Password authentication */
-         if (ctx->auth_data && ctx->auth_data_len) {
-           auth_data = strdup(ctx->auth_data);
-           auth_data_len = ctx->auth_data_len;
-           break;
-         }
-         break;
-
-       case SILC_AUTH_PUBLIC_KEY:
-         {
-           /* Public key authentication */
-           silc_server_get_public_key_auth(server, &auth_data, &auth_data_len,
-                                           ctx->ske);
-           break;
-         }
-       }
-
-       payload_len = 4 + auth_data_len;
-       packet = silc_buffer_alloc(payload_len);
-       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-       silc_buffer_format(packet,
-                          SILC_STR_UI_SHORT(payload_len),
-                          SILC_STR_UI_SHORT(server->server_type
-                                             == SILC_SERVER ?
-                                             SILC_SOCKET_TYPE_SERVER :
-                                             SILC_SOCKET_TYPE_ROUTER),
-                          SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
-                          SILC_STR_END);
-
-       /* Send the packet to server */
-       silc_server_packet_send(server, ctx->sock,
-                               SILC_PACKET_CONNECTION_AUTH, 0,
-                               packet->data, packet->len, TRUE);
-
-       if (auth_data) {
-         memset(auth_data, 0, auth_data_len);
-         silc_free(auth_data);
-       }
-       silc_buffer_free(packet);
-
-       /* Next state is end of protocol */
-       protocol->state = SILC_PROTOCOL_STATE_END;
-      }
-    }
-    break;
-
-  case SILC_PROTOCOL_STATE_END:
-    {
-      /*
-       * End protocol
-       */
-      unsigned char ok[4];
-
-      SILC_PUT32_MSB(SILC_AUTH_OK, ok);
-
-      /* Authentication successful */
-      silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS,
-                             0, ok, 4, TRUE);
-
-      /* Unregister the timeout task since the protocol has ended.
-        This was the timeout task to be executed if the protocol is
-        not completed fast enough. */
-      if (ctx->timeout_task)
-       silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
-      /* Assure that after calling final callback there cannot be pending
-        executions for this protocol anymore. This just unregisters any
-        timeout callbacks for this protocol. */
-      silc_protocol_cancel(protocol, server->schedule);
-
-      /* Protocol has ended, call the final callback */
-      if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->schedule);
-      else
-       silc_protocol_free(protocol);
-    }
-    break;
-  case SILC_PROTOCOL_STATE_ERROR:
-    {
-      /*
-       * Error. Send notify to remote.
-       */
-      unsigned char error[4];
-
-      /* Authentication failed */
-      SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
-      silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
-                             0, error, 4, TRUE);
-
-      /* Unregister the timeout task since the protocol has ended.
-        This was the timeout task to be executed if the protocol is
-        not completed fast enough. */
-      if (ctx->timeout_task)
-       silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
-      /* Assure that after calling final callback there cannot be pending
-        executions for this protocol anymore. This just unregisters any
-        timeout callbacks for this protocol. */
-      silc_protocol_cancel(protocol, server->schedule);
-
-      /* On error the final callback is always called. */
-      if (protocol->final_callback)
-       silc_protocol_execute_final(protocol, server->schedule);
-      else
-       silc_protocol_free(protocol);
-    }
-    break;
-
-  case SILC_PROTOCOL_STATE_FAILURE:
-    /*
-     * We have received failure from remote
-     */
-
-    SILC_LOG_ERROR(("Received Authentication Failure"));
-
-    /* Unregister the timeout task since the protocol has ended.
-       This was the timeout task to be executed if the protocol is
-       not completed fast enough. */
-    if (ctx->timeout_task)
-      silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
-    /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any
-       timeout callbacks for this protocol. */
-    silc_protocol_cancel(protocol, server->schedule);
-
-    /* On error the final callback is always called. */
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
-    break;
-
-  case SILC_PROTOCOL_STATE_UNKNOWN:
-    break;
-  }
-}
-
-/*
- * Re-key protocol routines
- */
-
-/* Actually takes the new keys into use. */
-
-static void
-silc_server_protocol_rekey_validate(SilcServer server,
-                                   SilcServerRekeyInternalContext *ctx,
-                                   SilcIDListData idata,
-                                   SilcSKEKeyMaterial *keymat,
-                                   bool send)
-{
-  if (ctx->responder == TRUE) {
-    if (send) {
-      silc_cipher_set_key(idata->send_key, keymat->receive_enc_key,
-                         keymat->enc_key_len);
-      silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
-      silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key,
-                       keymat->hmac_key_len);
-    } else {
-      silc_cipher_set_key(idata->receive_key, keymat->send_enc_key,
-                         keymat->enc_key_len);
-      silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
-      silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key,
-                       keymat->hmac_key_len);
-    }
-  } else {
-    if (send) {
-      silc_cipher_set_key(idata->send_key, keymat->send_enc_key,
-                         keymat->enc_key_len);
-      silc_cipher_set_iv(idata->send_key, keymat->send_iv);
-      silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key,
-                       keymat->hmac_key_len);
-    } else {
-      silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key,
-                         keymat->enc_key_len);
-      silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
-      silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key,
-                       keymat->hmac_key_len);
-    }
-  }
-
-  /* Save the current sending encryption key */
-  if (!send) {
-    memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
-    silc_free(idata->rekey->send_enc_key);
-    idata->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
-                                            keymat->enc_key_len / 8);
-    idata->rekey->enc_key_len = keymat->enc_key_len / 8;
-  }
-}
-
-/* This function actually re-generates (when not using PFS) the keys and
-   takes them into use. */
-
-void silc_server_protocol_rekey_generate(SilcServer server,
-                                        SilcServerRekeyInternalContext *ctx,
-                                        bool send)
-{
-  SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
-  SilcSKEKeyMaterial *keymat;
-  SilcUInt32 key_len = silc_cipher_get_key_len(idata->send_key);
-  SilcUInt32 hash_len = silc_hash_len(idata->hash);
-
-  SILC_LOG_DEBUG(("Generating new %s session keys (no PFS)",
-                 send ? "sending" : "receiving"));
-
-  /* Generate the new key */
-  keymat = silc_calloc(1, sizeof(*keymat));
-  silc_ske_process_key_material_data(idata->rekey->send_enc_key,
-                                    idata->rekey->enc_key_len,
-                                    16, key_len, hash_len,
-                                    idata->hash, keymat);
-
-  /* Set the keys into use */
-  silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
-
-  silc_ske_free_key_material(keymat);
-}
-
-/* This function actually re-generates (with PFS) the keys and
-   takes them into use. */
-
-void
-silc_server_protocol_rekey_generate_pfs(SilcServer server,
-                                       SilcServerRekeyInternalContext *ctx,
-                                       bool send)
-{
-  SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
-  SilcSKEKeyMaterial *keymat;
-  SilcUInt32 key_len = silc_cipher_get_key_len(idata->send_key);
-  SilcUInt32 hash_len = silc_hash_len(idata->hash);
-  unsigned char *tmpbuf;
-  SilcUInt32 klen;
-
-  SILC_LOG_DEBUG(("Generating new %s session keys (with PFS)",
-                 send ? "sending" : "receiving"));
-
-  /* Encode KEY to binary data */
-  tmpbuf = silc_mp_mp2bin(ctx->ske->KEY, 0, &klen);
-
-  /* Generate the new key */
-  keymat = silc_calloc(1, sizeof(*keymat));
-  silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len,
-                                    idata->hash, keymat);
-
-  /* Set the keys into use */
-  silc_server_protocol_rekey_validate(server, ctx, idata, keymat, send);
-
-  memset(tmpbuf, 0, klen);
-  silc_free(tmpbuf);
-  silc_ske_free_key_material(keymat);
-}
-
-/* Packet sending callback. This function is provided as packet sending
-   routine to the Key Exchange functions. */
-
-static void
-silc_server_protocol_rekey_send_packet(SilcSKE ske,
-                                      SilcBuffer packet,
-                                      SilcPacketType type,
-                                      void *context)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerRekeyInternalContext *ctx =
-    (SilcServerRekeyInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-
-  /* Send the packet immediately */
-  silc_server_packet_send(server, ctx->sock,
-                         type, 0, packet->data, packet->len, FALSE);
-}
-
-/* Performs re-key as defined in the SILC protocol specification. */
-
-SILC_TASK_CALLBACK(silc_server_protocol_rekey)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerRekeyInternalContext *ctx =
-    (SilcServerRekeyInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-  SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
-  SilcSKEStatus status;
-
-  if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
-    protocol->state = SILC_PROTOCOL_STATE_START;
-
-  SILC_LOG_DEBUG(("Current protocol state %d", protocol->state));
-
-  switch(protocol->state) {
-  case SILC_PROTOCOL_STATE_START:
-    {
-      /*
-       * Start protocol.
-       */
-
-      if (ctx->responder == TRUE) {
-       /*
-        * We are receiving party
-        */
-
-       if (ctx->pfs == TRUE) {
-         /*
-          * Use Perfect Forward Secrecy, ie. negotiate the key material
-          * using the SKE protocol.
-          */
-
-         if (!ctx->packet) {
-           SILC_LOG_ERROR(("Error during Re-key, with %s (%s)",
-                           ctx->sock->hostname, ctx->sock->ip));
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 0, 300000);
-           return;
-         }
-
-         if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
-           SILC_LOG_ERROR(("Error during Re-key (R PFS): re-key state is "
-                           "incorrect (received %d, expected %d packet), "
-                           "with %s (%s)", ctx->packet->type,
-                           SILC_PACKET_KEY_EXCHANGE_1, ctx->sock->hostname,
-                           ctx->sock->ip));
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 0, 300000);
-           return;
-         }
-
-         ctx->ske = silc_ske_alloc(server->rng, server);
-         ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
-         silc_ske_group_get_by_number(idata->rekey->ske_group,
-                                      &ctx->ske->prop->group);
-
-         silc_ske_set_callbacks(ctx->ske,
-                                silc_server_protocol_rekey_send_packet,
-                                NULL, NULL, NULL, silc_ske_check_version,
-                                context);
-
-         status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
-         if (status != SILC_SKE_STATUS_OK) {
-           SILC_LOG_ERROR(("Error (%s) during Re-key (R PFS), with %s (%s)",
-                           silc_ske_map_status(status), ctx->sock->hostname,
-                           ctx->sock->ip));
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 0, 300000);
-           return;
-         }
-
-         /* Advance the protocol state */
-         protocol->state++;
-         silc_protocol_execute(protocol, server->schedule, 0, 0);
-       } else {
-         /*
-          * Do normal and simple re-key.
-          */
-
-         /* Send the REKEY_DONE to indicate we will take new keys into use */
-         silc_server_packet_queue_purge(server, ctx->sock);
-         silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
-                                 0, NULL, 0, FALSE);
-
-         /* After we send REKEY_DONE we must set the sending encryption
-            key to the new key since all packets after this packet must
-            encrypted with the new key. */
-         silc_server_protocol_rekey_generate(server, ctx, TRUE);
-         silc_server_packet_queue_purge(server, ctx->sock);
-
-         /* The protocol ends in next stage. */
-         protocol->state = SILC_PROTOCOL_STATE_END;
-       }
-
-      } else {
-       /*
-        * We are the initiator of this protocol
-        */
-
-       /* Start the re-key by sending the REKEY packet */
-       silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY,
-                               0, NULL, 0, FALSE);
-
-       if (ctx->pfs == TRUE) {
-         /*
-          * Use Perfect Forward Secrecy, ie. negotiate the key material
-          * using the SKE protocol.
-          */
-         ctx->ske = silc_ske_alloc(server->rng, server);
-         ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
-         silc_ske_group_get_by_number(idata->rekey->ske_group,
-                                      &ctx->ske->prop->group);
-
-         silc_ske_set_callbacks(ctx->ske,
-                                silc_server_protocol_rekey_send_packet,
-                                NULL, NULL, NULL, silc_ske_check_version,
-                                context);
-
-         status = silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0);
-         if (status != SILC_SKE_STATUS_OK) {
-           SILC_LOG_ERROR(("Error (%s) during Re-key (I PFS), with %s (%s)",
-                           silc_ske_map_status(status), ctx->sock->hostname,
-                           ctx->sock->ip));
-           protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 0, 300000);
-           return;
-         }
-
-         /* Advance the protocol state */
-         protocol->state++;
-       } else {
-         /*
-          * Do normal and simple re-key.
-          */
-
-         /* Send the REKEY_DONE to indicate we will take new keys into use
-            now. */
-         silc_server_packet_queue_purge(server, ctx->sock);
-         silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
-                                 0, NULL, 0, FALSE);
-
-         /* After we send REKEY_DONE we must set the sending encryption
-            key to the new key since all packets after this packet must
-            encrypted with the new key. */
-         silc_server_protocol_rekey_generate(server, ctx, TRUE);
-         silc_server_packet_queue_purge(server, ctx->sock);
-
-         /* The protocol ends in next stage. */
-         protocol->state = SILC_PROTOCOL_STATE_END;
-       }
-      }
-    }
-    break;
-
-  case 2:
-    /*
-     * Second state, used only when doing re-key with PFS.
-     */
-    if (ctx->responder == TRUE) {
-      if (ctx->pfs == TRUE) {
-       /*
-        * Send our KE packet to the initiator now that we've processed
-        * the initiator's KE packet.
-        */
-       status = silc_ske_responder_finish(ctx->ske, NULL, NULL,
-                                          SILC_SKE_PK_TYPE_SILC);
-       if (status != SILC_SKE_STATUS_OK) {
-         SILC_LOG_ERROR(("Error (%s) during Re-key (R PFS), with %s (%s)",
-                         silc_ske_map_status(status), ctx->sock->hostname,
-                         ctx->sock->ip));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-      }
-
-    } else {
-      if (ctx->pfs == TRUE) {
-       /*
-        * The packet type must be KE packet
-        */
-       if (!ctx->packet) {
-         SILC_LOG_ERROR(("Error during Re-key, with %s (%s)",
-                         ctx->sock->hostname, ctx->sock->ip));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
-         SILC_LOG_ERROR(("Error during Re-key (I PFS): re-key state is "
-                         "incorrect (received %d, expected %d packet), "
-                         "with %s (%s)", ctx->packet->type,
-                         SILC_PACKET_KEY_EXCHANGE_2, ctx->sock->hostname,
-                         ctx->sock->ip));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-
-       status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
-       if (status != SILC_SKE_STATUS_OK) {
-         SILC_LOG_ERROR(("Error (%s) during Re-key (I PFS), with %s (%s)",
-                         silc_ske_map_status(status), ctx->sock->hostname,
-                         ctx->sock->ip));
-         protocol->state = SILC_PROTOCOL_STATE_ERROR;
-         silc_protocol_execute(protocol, server->schedule, 0, 300000);
-         return;
-       }
-      }
-    }
-
-    /* Send the REKEY_DONE to indicate we will take new keys into use
-       now. */
-    silc_server_packet_queue_purge(server, ctx->sock);
-    silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
-                           0, NULL, 0, FALSE);
-
-    /* After we send REKEY_DONE we must set the sending encryption
-       key to the new key since all packets after this packet must
-       encrypted with the new key. */
-    silc_server_protocol_rekey_generate_pfs(server, ctx, TRUE);
-    silc_server_packet_queue_purge(server, ctx->sock);
-
-    /* The protocol ends in next stage. */
-    protocol->state = SILC_PROTOCOL_STATE_END;
-    break;
-
-  case SILC_PROTOCOL_STATE_END:
-    /*
-     * End protocol
-     */
-
-    if (!ctx->packet) {
-      SILC_LOG_ERROR(("Error during Re-key, with %s (%s)",
-                    ctx->sock->hostname, ctx->sock->ip));
-      protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute(protocol, server->schedule, 0, 300000);
-      return;
-    }
-
-    if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
-      SILC_LOG_ERROR(("Error during Re-key (%s PFS): re-key state is "
-                     "incorrect (received %d, expected %d packet), "
-                     "with %s (%s)", ctx->responder ? "R" : "I",
-                     ctx->packet->type, SILC_PACKET_REKEY_DONE,
-                     ctx->sock->hostname, ctx->sock->ip));
-      protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute(protocol, server->schedule, 0, 300000);
-      return;
-    }
-
-    /* We received the REKEY_DONE packet and all packets after this is
-       encrypted with the new key so set the decryption key to the new key */
-    if (ctx->pfs == TRUE)
-      silc_server_protocol_rekey_generate_pfs(server, ctx, FALSE);
-    else
-      silc_server_protocol_rekey_generate(server, ctx, FALSE);
-    silc_server_packet_queue_purge(server, ctx->sock);
-
-    /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any
-       timeout callbacks for this protocol. */
-    silc_protocol_cancel(protocol, server->schedule);
-
-    /* Protocol has ended, call the final callback */
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
-    break;
-
-  case SILC_PROTOCOL_STATE_ERROR:
-    /*
-     * Error occured
-     */
-
-    if (ctx->pfs == TRUE)
-      /* Send abort notification */
-      silc_ske_abort(ctx->ske, ctx->ske->status);
-
-    /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any
-       timeout callbacks for this protocol. */
-    silc_protocol_cancel(protocol, server->schedule);
-
-    /* On error the final callback is always called. */
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
-    break;
-
-  case SILC_PROTOCOL_STATE_FAILURE:
-    /*
-     * We have received failure from remote
-     */
-
-    SILC_LOG_ERROR(("Error during Re-Key: received Failure"));
-
-    /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any
-       timeout callbacks for this protocol. */
-    silc_protocol_cancel(protocol, server->schedule);
-
-    /* On error the final callback is always called. */
-    if (protocol->final_callback)
-      silc_protocol_execute_final(protocol, server->schedule);
-    else
-      silc_protocol_free(protocol);
-    break;
-
-  case SILC_PROTOCOL_STATE_UNKNOWN:
-    break;
-  }
-
-}
-
-/* Registers protocols used in server. */
-
-void silc_server_protocols_register(void)
-{
-  silc_protocol_register(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
-                        silc_server_protocol_connection_auth);
-  silc_protocol_register(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
-                        silc_server_protocol_key_exchange);
-  silc_protocol_register(SILC_PROTOCOL_SERVER_REKEY,
-                        silc_server_protocol_rekey);
-  silc_protocol_register(SILC_PROTOCOL_SERVER_BACKUP,
-                        silc_server_protocol_backup);
-}
-
-/* Unregisters protocols */
-
-void silc_server_protocols_unregister(void)
-{
-  silc_protocol_unregister(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
-                          silc_server_protocol_connection_auth);
-  silc_protocol_unregister(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
-                          silc_server_protocol_key_exchange);
-  silc_protocol_unregister(SILC_PROTOCOL_SERVER_REKEY,
-                          silc_server_protocol_rekey);
-  silc_protocol_unregister(SILC_PROTOCOL_SERVER_BACKUP,
-                          silc_server_protocol_backup);
-}
diff --git a/apps/silcd/protocol.h b/apps/silcd/protocol.h
deleted file mode 100644 (file)
index 3c184ab..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-
-  protocol.h
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 1997 - 2003 Pekka Riikonen
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; 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
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-*/
-
-#ifndef PROTOCOL_H
-#define PROTOCOL_H
-
-/* SILC client protocol types */
-#define SILC_PROTOCOL_SERVER_NONE               0
-#define SILC_PROTOCOL_SERVER_CONNECTION_AUTH    1
-#define SILC_PROTOCOL_SERVER_KEY_EXCHANGE       2
-#define SILC_PROTOCOL_SERVER_REKEY              3
-#define SILC_PROTOCOL_SERVER_BACKUP             4
-/* #define SILC_PROTOCOL_SERVER_MAX             255 */
-
-/* Internal context for Key Exchange protocol. */
-typedef struct {
-  void *server;
-  void *context;
-  SilcSocketConnection sock;
-  SilcRng rng;
-
-  /* TRUE if we are receiveing part of the protocol */
-  bool responder;
-
-  /* Destinations ID taken from authenticataed packet so that we can
-     get the destinations ID. */
-  void *dest_id;
-  SilcIdType dest_id_type;
-
-  /* Pointers to the configurations. Defined only when responder is TRUE */
-  SilcServerConfigRef cconfig;
-  SilcServerConfigRef sconfig;
-  SilcServerConfigRef rconfig;
-
-  SilcTask timeout_task;
-  SilcPacketContext *packet;
-  SilcSKESecurityPropertyFlag flags;
-  SilcSKE ske;
-  SilcSKEKeyMaterial *keymat;
-} SilcServerKEInternalContext;
-
-/* Internal context for connection authentication protocol */
-typedef struct {
-  void *server;
-  void *context;
-  SilcSocketConnection sock;
-
-  /* TRUE if we are receiving part of the protocol */
-  bool responder;
-
-  /* SKE object from Key Exchange protocol. */
-  SilcSKE ske;
-
-  /* Authentication method and data if we alreay know it. This is filled
-     before starting the protocol if we know the authentication data.
-     Otherwise these are and remain NULL. Used when we are initiating. */
-  SilcUInt32 auth_meth;
-  void *auth_data;
-  SilcUInt32 auth_data_len;
-
-  /* Destinations ID from KE protocol context */
-  void *dest_id;
-  SilcIdType dest_id_type;
-
-  /* Pointers to the configurations. Defined only when responder is TRUE */
-  SilcServerConfigRef cconfig;
-  SilcServerConfigRef sconfig;
-  SilcServerConfigRef rconfig;
-
-  SilcTask timeout_task;
-  SilcPacketContext *packet;
-  SilcUInt16 conn_type;
-} SilcServerConnAuthInternalContext;
-
-/* Internal context for the rekey protocol */
-typedef struct {
-  void *server;
-  void *context;
-  SilcSocketConnection sock;
-  bool responder;                  /* TRUE if we are receiving party */
-  bool pfs;                        /* TRUE if PFS is to be used */
-  SilcSKE ske;                     /* Defined if PFS is used */
-  SilcPacketContext *packet;
-  SilcTask timeout_task;
-} SilcServerRekeyInternalContext;
-
-/* Prototypes */
-void silc_server_protocols_register(void);
-void silc_server_protocols_unregister(void);
-int silc_server_protocol_ke_set_keys(SilcServer server,
-                                    SilcSKE ske,
-                                    SilcSocketConnection sock,
-                                    SilcSKEKeyMaterial *keymat,
-                                    SilcCipher cipher,
-                                    SilcPKCS pkcs,
-                                    SilcHash hash,
-                                    SilcHmac hmac,
-                                    SilcSKEDiffieHellmanGroup group,
-                                    bool is_responder);
-
-#endif
index 5488bb315659a5417fbaf692ecbf5ae8b065e807..f32417c7f5657a7ba2ced36ac5504a684ee6ca7a 100644 (file)
@@ -68,7 +68,7 @@ SilcServerEntry silc_server_route_check(SilcUInt32 dest,
    If we are normal server then this just returns our primary route. If
    we are router we will do route lookup. */
 
-SilcSocketConnection silc_server_route_get(SilcServer server, void *id,
+SilcPacketStream silc_server_route_get(SilcServer server, void *id,
                                           SilcIdType id_type)
 {
   if (server->server_type == SILC_ROUTER) {
@@ -98,10 +98,10 @@ SilcSocketConnection silc_server_route_get(SilcServer server, void *id,
 
     router = silc_server_route_check(dest, port);
     if (router)
-        return (SilcSocketConnection)router->connection;
+      return router->connection;
   }
 
   return (server->id_entry->router) 
-       ? (SilcSocketConnection)server->id_entry->router->connection
+       ? server->id_entry->router->connection
        : NULL;
 }
index 0e78e739a4b66f91f57aaaa16a4a3bea2cdf462b..148adffabe4f1e4afbd1ca7bca808921db0c7998 100644 (file)
@@ -73,7 +73,7 @@ void silc_server_route_add(SilcUInt32 index, unsigned int dest,
                           SilcServerEntry router);
 SilcServerEntry silc_server_route_check(SilcUInt32 dest, 
                                        SilcUInt16 port);
-SilcSocketConnection silc_server_route_get(SilcServer server, void *id,
+SilcPacketStream silc_server_route_get(SilcServer server, void *id,
                                           SilcIdType id_type);
 
 #endif
index 92afbb91b5a9b62d115b9c41fc74d7df25f0eaac..5c9078a28af5e94d7427b641b1ded83987077876 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   GNU General Public License for more details.
 
 */
-/*
- * This is the actual SILC server than handles everything relating to
- * servicing the SILC connections. This is also a SILC router as a router
- * is also normal server.
- */
-/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
 
-/* Static prototypes */
-SILC_TASK_CALLBACK(silc_server_rehash_close_connection);
-SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
-SILC_TASK_CALLBACK(silc_server_connect_router);
-SILC_TASK_CALLBACK(silc_server_connect_to_router_second);
-SILC_TASK_CALLBACK(silc_server_connect_to_router_final);
-SILC_TASK_CALLBACK(silc_server_accept_new_connection);
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_second);
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_final);
-SILC_TASK_CALLBACK(silc_server_packet_process);
-SILC_TASK_CALLBACK(silc_server_packet_parse_real);
-SILC_TASK_CALLBACK(silc_server_close_connection_final);
-SILC_TASK_CALLBACK(silc_server_free_client_data_timeout);
-SILC_TASK_CALLBACK(silc_server_timeout_remote);
-SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
+/************************* Types and definitions ***************************/
+
 SILC_TASK_CALLBACK(silc_server_get_stats);
 SILC_TASK_CALLBACK(silc_server_connect_router);
+SILC_TASK_CALLBACK(silc_server_do_rekey);
+static void silc_server_accept_new_connection(SilcNetStatus status,
+                                             SilcStream stream,
+                                             void *context);
+static void silc_server_packet_parse_type(SilcServer server,
+                                         SilcPacketStream sock,
+                                         SilcPacket packet);
 
-/* Allocates a new SILC server object. This has to be done before the server
-   can be used. After allocation one must call silc_server_init to initialize
-   the server. The new allocated server object is returned to the new_server
-   argument. */
-
-int silc_server_alloc(SilcServer *new_server)
-{
-  SilcServer server;
-
-  SILC_LOG_DEBUG(("Allocating new server object"));
-
-  server = silc_calloc(1, sizeof(*server));
-  server->server_type = SILC_SERVER;
-  server->standalone = TRUE;
-  server->local_list = silc_calloc(1, sizeof(*server->local_list));
-  server->global_list = silc_calloc(1, sizeof(*server->global_list));
-  server->pending_commands = silc_dlist_init();
-#ifdef SILC_SIM
-  server->sim = silc_dlist_init();
-#endif
-
-  *new_server = server;
 
-  return TRUE;
-}
+/************************ Static utility functions **************************/
 
-/* Free's the SILC server object. This is called at the very end before
-   the program ends. */
+/* SKE public key verification callback */
 
-void silc_server_free(SilcServer server)
+static void
+silc_server_verify_key(SilcSKE ske,
+                      SilcPublicKey public_key,
+                      void *context,
+                      SilcSKEVerifyCbCompletion completion,
+                      void *completion_context)
 {
-  SilcIDCacheList list;
-  SilcIDCacheEntry cache;
+  SilcPacketStream sock = context;
+  SilcUnknownEntry entry = silc_packet_get_context(sock);
 
-  if (!server)
-    return;
+  SILC_LOG_DEBUG(("Verifying public key"));
 
-#ifdef SILC_SIM
-  {
-    SilcSim sim;
-    silc_dlist_start(server->sim);
-    while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
-      silc_dlist_del(server->sim, sim);
-      silc_sim_close(sim);
-      silc_sim_free(sim);
-    }
-    silc_dlist_uninit(server->sim);
+  if (silc_pkcs_get_type(public_key) != SILC_SKE_PK_TYPE_SILC) {
+    SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d",
+                     entry->hostname, entry->ip, entry->port,
+                     silc_pkcs_get_type(public_key)));
+    completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
+              completion_context);
+    return;
   }
-#endif
 
-  silc_server_backup_free(server);
-  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);
+  /* We accept all keys without explicit verification */
+  completion(ske, SILC_SKE_STATUS_OK, completion_context);
+}
 
-  /* 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);
 
-  if (server->pk_hash)
-    silc_hash_table_free(server->pk_hash);
+/************************ Packet engine callbacks ***************************/
 
-  /* 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);
+/* Packet engine callback to receive a packet */
 
+static SilcBool silc_server_packet_receive(SilcPacketEngine engine,
+                                          SilcPacketStream stream,
+                                          SilcPacket packet,
+                                          void *callback_context,
+                                          void *stream_context)
+{
+  SilcServer server = callback_context;
+  SilcIDListData idata = stream_context;
 
-  /* 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);
+  /* Packets we do not handle */
+  switch (packet->type) {
+  case SILC_PACKET_HEARTBEAT:
+  case SILC_PACKET_SUCCESS:
+  case SILC_PACKET_FAILURE:
+  case SILC_PACKET_REJECT:
+  case SILC_PACKET_KEY_EXCHANGE:
+  case SILC_PACKET_KEY_EXCHANGE_1:
+  case SILC_PACKET_KEY_EXCHANGE_2:
+  case SILC_PACKET_REKEY_DONE:
+  case SILC_PACKET_CONNECTION_AUTH:
+    return FALSE;
+    break;
   }
-  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);
-  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_table_free(server->watcher_list_pk);
+  /* Only specific packets can come without source ID present. */
+  if ((!packet->src_id ||
+       !(idata->status & SILC_IDLIST_STATUS_REGISTERED)) &&
+      packet->type != SILC_PACKET_NEW_CLIENT &&
+      packet->type != SILC_PACKET_NEW_SERVER &&
+      packet->type != SILC_PACKET_DISCONNECT)
+    return FALSE;
 
-  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();
+  /* NEW_CLIENT and NEW_SERVER are accepted only without source ID
+     and for unregistered connection. */
+  if (packet->src_id && (packet->type == SILC_PACKET_NEW_CLIENT ||
+                        packet->type == SILC_PACKET_NEW_SERVER) &&
+      (idata->status & SILC_IDLIST_STATUS_REGISTERED))
+    return FALSE;
 
-  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);
+  /* Process packet */
+  silc_server_packet_parse_type(server, stream, packet);
+
+  return TRUE;
 }
 
-/* Creates a new server listener. */
+/* Packet engine callback to indicate end of stream */
 
-static bool silc_server_listen(SilcServer server, const char *server_ip,
-                              SilcUInt16 port, int *sock)
+static void silc_server_packet_eos(SilcPacketEngine engine,
+                                  SilcPacketStream stream,
+                                  void *callback_context,
+                                  void *stream_context)
 {
-  *sock = silc_net_create_server(port, server_ip);
-  if (*sock < 0) {
-    SILC_SERVER_LOG_ERROR(("Could not create server listener: %s on %hu",
-                       server_ip, port));
-    return FALSE;
-  }
-  return TRUE;
+  SILC_LOG_DEBUG(("End of stream received"));
 }
 
-/* Adds a secondary listener. */
+/* Packet engine callback to indicate error */
 
-bool silc_server_init_secondary(SilcServer server)
+static void silc_server_packet_error(SilcPacketEngine engine,
+                                    SilcPacketStream stream,
+                                    SilcPacketError error,
+                                    void *callback_context,
+                                    void *stream_context)
 {
-  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;
+/* Packet stream callbacks */
+static SilcPacketCallbacks silc_server_stream_cbs =
+{
+  silc_server_packet_receive,
+  silc_server_packet_eos,
+  silc_server_packet_error
+};
 
-    /* Set socket to non-blocking mode */
-    silc_net_set_socket_nonblock(sock_list[sock]);
+/* Parses the packet type and calls what ever routines the packet type
+   requires. This is done for all incoming packets. */
 
-    /* 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;
-    SILC_SET_LISTENER(newsocket);
+static void silc_server_packet_parse_type(SilcServer server,
+                                         SilcPacketStream sock,
+                                         SilcPacket packet)
+{
+  SilcPacketType type = packet->type;
+  SilcIDListData idata = silc_packet_get_context(sock);
 
-    /* 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);
+  SILC_LOG_DEBUG(("Received %s packet [flags %d]",
+                 silc_get_packet_name(type), packet->flags));
 
-    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);
-  }
+  /* Parse the packet type */
+  switch (type) {
+  case SILC_PACKET_NOTIFY:
+    /*
+     * Received notify packet. Server can receive notify packets from
+     * router. Server then relays the notify messages to clients if needed.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      silc_server_notify_list(server, sock, packet);
+    else
+      silc_server_notify(server, sock, packet);
+    break;
 
-  return TRUE;
+    /*
+     * Private Message packets
+     */
+  case SILC_PACKET_PRIVATE_MESSAGE:
+    /*
+     * Received private message packet. The packet is coming from either
+     * client or server.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    idata->last_receive = time(NULL);
+    silc_server_private_message(server, sock, packet);
+    break;
 
- err:
-  do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
-  return FALSE;
-}
+    /*
+     * Channel packets
+     */
+  case SILC_PACKET_CHANNEL_MESSAGE:
+    /*
+     * Received channel message. Channel messages are special packets
+     * (although probably most common ones) thus they are handled
+     * specially.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    idata->last_receive = time(NULL);
+    silc_server_channel_message(server, sock, packet);
+    break;
 
-/* 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
-   one should call silc_server_run to start the server. This returns TRUE
-   when everything is ok to run the server. Configuration file must be
-   read and parsed before calling this. */
+    /*
+     * Command packets
+     */
+  case SILC_PACKET_COMMAND:
+    /*
+     * Recived command. Processes the command request and allocates the
+     * command context and calls the command.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    server->stat.commands_received++;
+    silc_server_command_process(server, sock, packet);
+    break;
 
-bool silc_server_init(SilcServer server)
-{
-  int sock = -1;
-  SilcServerID *id;
-  SilcServerEntry id_entry;
-  SilcIDListPurge purge;
-  SilcSocketConnection newsocket = NULL;
+  case SILC_PACKET_COMMAND_REPLY:
+    /*
+     * Received command reply packet. Received command reply to command. It
+     * may be reply to command sent by us or reply to command sent by client
+     * that we've routed further.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    server->stat.commands_received++;
+    silc_server_command_reply(server, sock, packet);
+    break;
 
-  SILC_LOG_DEBUG(("Initializing server"));
+  case SILC_PACKET_DISCONNECT:
+    {
+      SilcStatus status;
+      char *message = NULL;
 
-  server->starttime = time(NULL);
+      if (packet->flags & SILC_PACKET_FLAG_LIST)
+       break;
+      if (silc_buffer_len(&packet->buffer) < 1)
+       break;
 
-  /* Take config object for us */
-  silc_server_config_ref(&server->config_ref, server->config,
-                        server->config);
+      status = (SilcStatus)packet->buffer.data[0];
+      if (silc_buffer_len(&packet->buffer) > 1 &&
+         silc_utf8_valid(packet->buffer.data + 1, silc_buffer_len(&packet->buffer) - 1))
+       message = silc_memdup(packet->buffer.data + 1,
+                             silc_buffer_len(&packet->buffer) - 1);
 
-#ifdef SILC_DEBUG
-  /* Set debugging on if configured */
-  if (server->config->debug_string) {
-    silc_log_debug(TRUE);
-    silc_log_set_debug_string(server->config->debug_string);
-  }
-#endif /* SILC_DEBUG */
+#if 0
+      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
+                    sock->ip, sock->hostname,
+                    silc_get_status_message(status), status,
+                    message ? message : ""));
+#endif
+      silc_free(message);
 
-  /* Steal public and private key from the config object */
-  server->public_key = server->config->server_info->public_key;
-  server->private_key = server->config->server_info->private_key;
-  server->config->server_info->public_key = NULL;
-  server->config->server_info->private_key = NULL;
-
-  /* Register all configured ciphers, PKCS and hash functions. */
-  if (!silc_server_config_register_ciphers(server))
-    silc_cipher_register_default();
-  if (!silc_server_config_register_pkcs(server))
-    silc_pkcs_register_default();
-  if (!silc_server_config_register_hashfuncs(server))
-    silc_hash_register_default();
-  if (!silc_server_config_register_hmacs(server))
-    silc_hmac_register_default();
-
-  /* Initialize random number generator for the server. */
-  server->rng = silc_rng_alloc();
-  silc_rng_init(server->rng);
-  silc_rng_global_init(server->rng);
-
-  /* Initialize hash functions for server to use */
-  silc_hash_alloc("md5", &server->md5hash);
-  silc_hash_alloc("sha1", &server->sha1hash);
-
-  /* Allocate PKCS context for local public and private keys */
-  if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
-    goto err;
-  silc_pkcs_public_key_set(server->pkcs, server->public_key);
-  silc_pkcs_private_key_set(server->pkcs, server->private_key);
-
-  /* Initialize the scheduler */
-  server->schedule = silc_schedule_init(server->config->param.connections_max,
-                                       server);
-  if (!server->schedule)
-    goto err;
-
-  /* First, register log files configuration for error output */
-  silc_server_config_setlogfiles(server);
-
-  /* Initialize ID caches */
-  server->local_list->clients =
-    silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
-                      server, FALSE, TRUE);
-  server->local_list->servers =
-    silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL, FALSE, TRUE);
-  server->local_list->channels =
-    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL, FALSE, TRUE);
-
-  /* These are allocated for normal server as well as these hold some
-     global information that the server has fetched from its router. For
-     router these are used as they are supposed to be used on router. */
-  server->global_list->clients =
-    silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
-                      server, FALSE, TRUE);
-  server->global_list->servers =
-    silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL, FALSE, TRUE);
-  server->global_list->channels =
-    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL, FALSE, TRUE);
-
-  /* Init watcher lists */
-  server->watcher_list =
-    silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
-                         silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
-                         NULL, NULL, TRUE);
-  if (!server->watcher_list)
-    goto err;
-  server->watcher_list_pk =
-    silc_hash_table_alloc(1, silc_hash_public_key, NULL,
-                         silc_hash_public_key_compare, NULL,
-                         NULL, NULL, TRUE);
-  if (!server->watcher_list_pk)
-    goto err;
-
-  /* Init public key list */
-  server->pk_hash =
-    silc_hash_table_alloc(0, silc_hash_public_key, NULL,
-                          silc_hash_public_key_compare, NULL,
-                          NULL, NULL, TRUE);
-
-  if (!server->pk_hash)
-    goto err;
+      /* Do not switch to backup in case of error */
+      server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
 
-  /* Create a listening server */
-  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;
+      /* If backup disconnected then mark that resuming will not be allowed */
+#if 0
+      if (server->server_type == SILC_ROUTER && !server->backup_router &&
+         sock->type == SILC_CONN_SERVER && sock->user_data) {
+       SilcServerEntry server_entry = sock->user_data;
+       if (server_entry->server_type == SILC_BACKUP_ROUTER)
+         server->backup_closed = TRUE;
+      }
 
-  /* Set socket to non-blocking mode */
-  silc_net_set_socket_nonblock(sock);
-  server->sock = sock;
+      /* Handle the disconnection from our end too */
+      if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
+       silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
+      silc_server_close_connection(server, sock);
+      server->backup_noswitch = FALSE;
+#endif
+    }
+    break;
 
-  /* Allocate the entire socket list that is used in server. Eventually
-     all connections will have entry in this table (it is a table of
-     pointers to the actual object that is allocated individually
-     later). */
-  server->sockets = silc_calloc(server->config->param.connections_max,
-                               sizeof(*server->sockets));
-  if (!server->sockets)
-    goto err;
+  case SILC_PACKET_CHANNEL_KEY:
+    /*
+     * Received key for channel. As channels are created by the router
+     * the keys are as well. We will distribute the key to all of our
+     * locally connected clients on the particular channel. Router
+     * never receives this channel and thus is ignored.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_channel_key(server, sock, packet);
+    break;
 
-  /* 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, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
-  server->sockets[sock] = newsocket;
-  SILC_SET_LISTENER(newsocket);
+  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+    /*
+     * Private message key packet.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_private_message_key(server, sock, packet);
+    break;
 
-  /* Perform name and address lookups to resolve the listenning address
-     and port. */
-  if (!silc_net_check_local_by_sock(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);
+  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+    /*
+     * Connection authentication request packet. When we receive this packet
+     * we will send to the other end information about our mandatory
+     * authentication method for the connection. This packet maybe received
+     * at any time.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_connection_auth_request(server, sock, packet);
+    break;
 
-  /* Create a Server ID for the server. */
-  silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
-  if (!id)
-    goto err;
+  case SILC_PACKET_NEW_ID:
+    /*
+     * Received New ID packet. This includes some new ID that has been
+     * created. It may be for client, server or channel. This is the way
+     * to distribute information about new registered entities in the
+     * SILC network.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      silc_server_new_id_list(server, sock, packet);
+    else
+      silc_server_new_id(server, sock, packet);
+    break;
 
-  server->id = id;
-  server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
-  server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
-  server->server_name = server->config->server_info->server_name;
-  server->config->server_info->server_name = NULL;
+  case SILC_PACKET_NEW_CLIENT:
+    /*
+     * Received new client packet. This includes client information that
+     * we will use to create initial client ID. After creating new
+     * ID we will send it to the client.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_new_client(server, sock, packet);
+    break;
 
-  /* Add ourselves to the server list. We don't have a router yet
-     beacuse we haven't established a route yet. It will be done later.
-     For now, NULL is sent as router. This allocates new entry to
-     the ID list. */
-  id_entry =
-    silc_idlist_add_server(server->local_list, strdup(server->server_name),
-                          server->server_type, server->id, NULL, NULL);
-  if (!id_entry) {
-    SILC_LOG_ERROR(("Could not add ourselves to cache"));
-    goto err;
-  }
-  id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+  case SILC_PACKET_NEW_SERVER:
+    /*
+     * Received new server packet. This includes Server ID and some other
+     * information that we may save. This is received after server has
+     * connected to us.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_new_server(server, sock, packet);
+    break;
 
-  /* Put the allocated socket pointer also to the entry allocated above
-     for fast back-referencing to the socket list. */
-  newsocket->user_data = (void *)id_entry;
-  id_entry->connection = (void *)newsocket;
-  server->id_entry = id_entry;
+  case SILC_PACKET_NEW_CHANNEL:
+    /*
+     * Received new channel packet. Information about new channel in the
+     * network are distributed using this packet.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      silc_server_new_channel_list(server, sock, packet);
+    else
+      silc_server_new_channel(server, sock, packet);
+    break;
 
-  /* Register protocols */
-  silc_server_protocols_register();
+  case SILC_PACKET_HEARTBEAT:
+    /*
+     * Received heartbeat.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    break;
 
-  /* Create connections to configured routers. */
-  silc_server_create_connections(server);
+  case SILC_PACKET_KEY_AGREEMENT:
+    /*
+     * Received heartbeat.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_key_agreement(server, sock, packet);
+    break;
 
-  /* 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,
-                        silc_server_accept_new_connection,
-                        (void *)server, 0, 0,
-                        SILC_TASK_FD,
-                        SILC_TASK_PRI_NORMAL);
+  case SILC_PACKET_REKEY:
+    /*
+     * Received re-key packet. The sender wants to regenerate the session
+     * keys.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    /* XXX handle rekey */
+    break;
 
-  if (silc_server_init_secondary(server) == FALSE)
-    goto err;
+  case SILC_PACKET_FTP:
+    /* FTP packet */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_ftp(server, sock, packet);
+    break;
 
-  server->listenning = TRUE;
+  case SILC_PACKET_RESUME_CLIENT:
+    /* Resume client */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_resume_client(server, sock, packet);
+    break;
 
-  /* If server connections has been configured then we must be router as
-     normal server cannot have server connections, only router connections. */
-  if (server->config->servers) {
-    SilcServerConfigServer *ptr = server->config->servers;
+  case SILC_PACKET_RESUME_ROUTER:
+    /* Resume router packet received. This packet is received for backup
+       router resuming protocol. */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+#if 0
+    silc_server_backup_resume_router(server, sock, packet);
+#endif
+    break;
 
-    server->server_type = SILC_ROUTER;
-    while (ptr) {
-      if (ptr->backup_router) {
-       server->server_type = SILC_BACKUP_ROUTER;
-       server->backup_router = TRUE;
-       server->id_entry->server_type = SILC_BACKUP_ROUTER;
-       break;
-      }
-      ptr = ptr->next;
-    }
+  default:
+    SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
+    break;
   }
+}
 
-  /* Register the ID Cache purge task. This periodically purges the ID cache
-     and removes the expired cache entries. */
+/****************************** Server API **********************************/
 
-  /* Clients local list */
-  server->purge_i = purge = silc_calloc(1, sizeof(*purge));
-  purge->cache = server->local_list->clients;
-  purge->timeout = 600;
-  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
-                        (void *)purge, purge->timeout, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+/* Allocates a new SILC server object. This has to be done before the server
+   can be used. After allocation one must call silc_server_init to initialize
+   the server. The new allocated server object is returned to the new_server
+   argument. */
 
-  /* Clients global list */
-  server->purge_g = purge = silc_calloc(1, sizeof(*purge));
-  purge->cache = server->global_list->clients;
-  purge->timeout = 300;
-  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
-                        (void *)purge, purge->timeout, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+SilcBool silc_server_alloc(SilcServer *new_server)
+{
+  SilcServer server;
 
-  /* If we are normal server we'll retrieve network statisticial information
-     once in a while from the router. */
-  if (server->server_type != SILC_ROUTER)
-    silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
-                          server, 10, 0, SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW);
+  SILC_LOG_DEBUG(("Allocating new server object"));
 
-  if (server->server_type == SILC_ROUTER)
-    server->stat.routers++;
+  server = silc_calloc(1, sizeof(*server));
+  if (!server)
+    return FALSE;
+  server->server_type = SILC_SERVER;
+  server->standalone = TRUE;
+  server->local_list = silc_calloc(1, sizeof(*server->local_list));
+  if (!server->local_list)
+    return FALSE;
+  server->global_list = silc_calloc(1, sizeof(*server->global_list));
+  if (!server->global_list)
+    return FALSE;
+  server->pending_commands = silc_dlist_init();
+  if (!server->pending_commands)
+    return FALSE;
+  server->listeners = silc_dlist_init();
+  if (!server->listeners)
+    return FALSE;
+  server->repository = silc_skr_alloc();
+  if (!server->repository)
+    return FALSE;
 
-  SILC_LOG_DEBUG(("Server initialized"));
+  *new_server = server;
 
-  /* We are done here, return succesfully */
   return TRUE;
-
- err:
-  silc_server_config_unref(&server->config_ref);
-  silc_net_close_server(sock);
-  return FALSE;
 }
 
-/* Task callback to close a socket connection after rehash */
+/* Free's the SILC server object. This is called at the very end before
+   the program ends. */
 
-SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
+void silc_server_free(SilcServer server)
 {
-  SilcServer server = context;
-  SilcSocketConnection sock = server->sockets[fd];
+  SilcList list;
+  SilcIDCacheEntry cache;
 
-  if (!sock)
+  if (!server)
     return;
 
-  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" :
-                 sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                 "Router")));
-  silc_schedule_task_del_by_context(server->schedule, sock);
-  silc_server_disconnect_remote(server, sock,
-                               SILC_STATUS_ERR_BANNED_FROM_SERVER,
-                               "This connection is removed from "
-                               "configuration");
-  if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock, NULL);
-}
-
-/* This function basically reads the config file again and switches the config
-   object pointed by the server object. After that, we have to fix various
-   things such as the server_name and the listening ports.
-   Keep in mind that we no longer have the root privileges at this point. */
-
-bool silc_server_rehash(SilcServer server)
-{
-  SilcServerConfig newconfig;
-
-  SILC_LOG_INFO(("Rehashing server"));
-
-  /* Reset the logging system */
-  silc_log_quick(TRUE);
-  silc_log_flush_all();
+  silc_server_backup_free(server);
+  silc_server_config_unref(&server->config_ref);
+  if (server->pk_hash)
+    silc_hash_table_free(server->pk_hash);
+  if (server->rng)
+    silc_rng_free(server->rng);
+  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);
 
-  /* Start the main rehash phase (read again the config file) */
-  newconfig = silc_server_config_alloc(server->config_file);
-  if (!newconfig) {
-    SILC_LOG_ERROR(("Rehash FAILED."));
-    return FALSE;
+  /* Delete all channels */
+  if (silc_idcache_get_all(server->local_list->channels, &list)) {
+    silc_list_start(list);
+    while ((cache = silc_list_get(list)))
+      silc_idlist_del_channel(server->local_list, cache->context);
   }
-
-  /* Reinit scheduler if necessary */
-  if (newconfig->param.connections_max > server->config->param.connections_max)
-    if (!silc_schedule_reinit(server->schedule,
-                             newconfig->param.connections_max))
-      return FALSE;
-
-  /* Fix the server_name field */
-  if (strcmp(server->server_name, newconfig->server_info->server_name)) {
-    silc_free(server->server_name);
-
-    /* Check server name */
-    server->server_name =
-      silc_identifier_check(newconfig->server_info->server_name,
-                           strlen(newconfig->server_info->server_name),
-                           SILC_STRING_LOCALE, 256, NULL);
-    if (!server->server_name) {
-      SILC_LOG_ERROR(("Malformed server name string '%s'",
-                     server->config->server_info->server_name));
-      return FALSE;
-    }
-
-    /* Update the idcache list with a fresh pointer */
-    silc_free(server->id_entry->server_name);
-    server->id_entry->server_name = strdup(server->server_name);
-    if (!silc_idcache_del_by_context(server->local_list->servers,
-                                    server->id_entry))
-      return FALSE;
-    if (!silc_idcache_add(server->local_list->servers,
-                         strdup(server->id_entry->server_name),
-                         server->id_entry->id, server->id_entry, 0, NULL))
-      return FALSE;
+  if (silc_idcache_get_all(server->global_list->channels, &list)) {
+    silc_list_start(list);
+    while ((cache = silc_list_get(list)))
+      silc_idlist_del_channel(server->global_list, cache->context);
   }
 
-  /* Set logging */
-  silc_server_config_setlogfiles(server);
-
-  /* Change new key pair if necessary */
-  if (newconfig->server_info->public_key &&
-      !silc_pkcs_public_key_compare(server->public_key,
-                                   newconfig->server_info->public_key)) {
-    silc_pkcs_public_key_free(server->public_key);
-    silc_pkcs_private_key_free(server->private_key);
-    server->public_key = newconfig->server_info->public_key;
-    server->private_key = newconfig->server_info->private_key;
-    newconfig->server_info->public_key = NULL;
-    newconfig->server_info->private_key = NULL;
-
-    /* Allocate PKCS context for local public and private keys */
-    silc_pkcs_free(server->pkcs);
-    if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
-      return FALSE;
-    silc_pkcs_public_key_set(server->pkcs, server->public_key);
-    silc_pkcs_private_key_set(server->pkcs, server->private_key);
+  /* Delete all clients */
+  if (silc_idcache_get_all(server->local_list->clients, &list)) {
+    silc_list_start(list);
+    while ((cache = silc_list_get(list)))
+      silc_idlist_del_client(server->local_list, cache->context);
+  }
+  if (silc_idcache_get_all(server->global_list->clients, &list)) {
+    silc_list_start(list);
+    while ((cache = silc_list_get(list)))
+      silc_idlist_del_client(server->global_list, cache->context);
   }
 
-  /* Check for unconfigured server and router connections and close
-     connections that were unconfigured. */
+  /* Delete all servers */
+  if (silc_idcache_get_all(server->local_list->servers, &list)) {
+    silc_list_start(list);
+    while ((cache = silc_list_get(list)))
+      silc_idlist_del_server(server->local_list, cache->context);
+  }
+  if (silc_idcache_get_all(server->global_list->servers, &list)) {
+    while ((cache = silc_list_get(list)))
+      silc_idlist_del_server(server->global_list, cache->context);
+  }
 
-  if (server->config->routers) {
-    SilcServerConfigRouter *ptr;
-    SilcServerConfigRouter *newptr;
-    bool found;
+  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_table_free(server->watcher_list_pk);
 
-    for (ptr = server->config->routers; ptr; ptr = ptr->next) {
-      found = FALSE;
+  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();
 
-      /* Check whether new config has this one too */
-      for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
-       if (silc_string_compare(newptr->host, ptr->host) &&
-           newptr->port == ptr->port &&
-           newptr->initiator == ptr->initiator) {
-         found = TRUE;
-         break;
-       }
-      }
+  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);
+}
 
-      if (!found && ptr->host) {
-       /* Remove this connection */
-       SilcSocketConnection sock;
-       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
-                                              ptr->host, ptr->port);
-       if (sock && !SILC_IS_LISTENER(sock))
-         silc_schedule_task_add(server->schedule, sock->sock,
-                                silc_server_rehash_close_connection,
-                                server, 0, 1, SILC_TASK_TIMEOUT,
-                                SILC_TASK_PRI_NORMAL);
-      }
-    }
+/* Creates a new server listener. */
+
+static SilcNetListener
+silc_server_listen(SilcServer server, const char *server_ip, SilcUInt16 port)
+{
+  SilcNetListener listener;
+
+  listener =
+    silc_net_tcp_create_listener(&server_ip, 1, port, TRUE,
+                                server->config->require_reverse_lookup,
+                                server->schedule,
+                                silc_server_accept_new_connection, server);
+  if (!listener) {
+    SILC_SERVER_LOG_ERROR(("Could not create server listener: %s on %hu",
+                          server_ip, port));
+    return NULL;
   }
 
-  if (server->config->servers) {
-    SilcServerConfigServer *ptr;
-    SilcServerConfigServer *newptr;
-    bool found;
+  return listener;
+}
 
-    for (ptr = server->config->servers; ptr; ptr = ptr->next) {
-      found = FALSE;
+/* Adds a secondary listener. */
 
-      /* Check whether new config has this one too */
-      for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
-       if (silc_string_compare(newptr->host, ptr->host)) {
-         found = TRUE;
-         break;
-       }
-      }
+SilcBool silc_server_init_secondary(SilcServer server)
+{
+#if 0
+  int sock = 0;
+  SilcPacketStream newsocket = NULL;
+  SilcServerConfigServerInfoInterface *interface;
 
-      if (!found && ptr->host) {
-       /* Remove this connection */
-       SilcSocketConnection sock;
-       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
-                                              ptr->host, 0);
-       if (sock && !SILC_IS_LISTENER(sock))
-         silc_schedule_task_add(server->schedule, sock->sock,
-                                silc_server_rehash_close_connection,
-                                server, 0, 1, SILC_TASK_TIMEOUT,
-                                SILC_TASK_PRI_NORMAL);
-      }
-    }
-  }
+  for (interface = server->config->server_info->secondary; interface;
+       interface = interface->next, sock++) {
 
-  if (server->config->clients) {
-    SilcServerConfigClient *ptr;
-    SilcServerConfigClient *newptr;
-    bool found;
+    if (!silc_server_listen(server,
+       interface->server_ip, interface->port, &sock_list[sock]))
+      goto err;
 
-    for (ptr = server->config->clients; ptr; ptr = ptr->next) {
-      found = FALSE;
+    /* Set socket to non-blocking mode */
+    silc_net_set_socket_nonblock(sock_list[sock]);
 
-      /* Check whether new config has this one too */
-      for (newptr = newconfig->clients; newptr; newptr = newptr->next) {
-       if (silc_string_compare(newptr->host, ptr->host)) {
-         found = TRUE;
-         break;
-       }
-      }
+    /* 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_CONN_SERVER, NULL, &newsocket);
+    server->sockets[sock_list[sock]] = newsocket;
+    SILC_SET_LISTENER(newsocket);
 
-      if (!found && ptr->host) {
-       /* Remove this connection */
-       SilcSocketConnection sock;
-       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_CLIENT,
-                                              ptr->host, 0);
-       if (sock)
-         silc_schedule_task_add(server->schedule, sock->sock,
-                                silc_server_rehash_close_connection,
-                                server, 0, 1, SILC_TASK_TIMEOUT,
-                                SILC_TASK_PRI_NORMAL);
+    /* 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);
   }
 
-  /* Create connections after rehash */
-  silc_server_create_connections(server);
+  return TRUE;
 
-  /* Check whether our router status has changed */
-  if (newconfig->servers) {
-    SilcServerConfigServer *ptr = newconfig->servers;
+ err:
+  do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
+#endif /* 0 */
+  return FALSE;
+}
 
-    server->server_type = SILC_ROUTER;
-    while (ptr) {
-      if (ptr->backup_router) {
-       server->server_type = SILC_BACKUP_ROUTER;
-       server->backup_router = TRUE;
-       server->id_entry->server_type = SILC_BACKUP_ROUTER;
-       break;
-      }
-      ptr = ptr->next;
-    }
-  }
+/* 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
+   one should call silc_server_run to start the server. This returns TRUE
+   when everything is ok to run the server. Configuration file must be
+   read and parsed before calling this. */
 
-  /* Our old config is gone now. We'll unreference our reference made in
-     silc_server_init and then destroy it since we are destroying it
-     underneath the application (layer which called silc_server_init). */
-  silc_server_config_unref(&server->config_ref);
-  silc_server_config_destroy(server->config);
+SilcBool silc_server_init(SilcServer server)
+{
+  SilcServerID *id;
+  SilcServerEntry id_entry;
+  SilcIDListPurge purge;
+  SilcNetListener listener;
+  SilcUInt16 *port;
+  char **ip;
 
-  /* Take new config context */
-  server->config = newconfig;
-  silc_server_config_ref(&server->config_ref, server->config, server->config);
+  SILC_LOG_DEBUG(("Initializing server"));
+
+  server->starttime = time(NULL);
+
+  /* Take config object for us */
+  silc_server_config_ref(&server->config_ref, server->config,
+                        server->config);
 
 #ifdef SILC_DEBUG
   /* Set debugging on if configured */
@@ -769,2490 +641,2008 @@ bool silc_server_rehash(SilcServer server)
   }
 #endif /* SILC_DEBUG */
 
-  SILC_LOG_DEBUG(("Server rehashed"));
+  /* Steal public and private key from the config object */
+  server->public_key = server->config->server_info->public_key;
+  server->private_key = server->config->server_info->private_key;
+  server->config->server_info->public_key = NULL;
+  server->config->server_info->private_key = NULL;
 
-  return TRUE;
-}
+  /* Register all configured ciphers, PKCS and hash functions. */
+  if (!silc_server_config_register_ciphers(server))
+    silc_cipher_register_default();
+  if (!silc_server_config_register_pkcs(server))
+    silc_pkcs_register_default();
+  if (!silc_server_config_register_hashfuncs(server))
+    silc_hash_register_default();
+  if (!silc_server_config_register_hmacs(server))
+    silc_hmac_register_default();
 
-/* The heart of the server. This runs the scheduler thus runs the server.
-   When this returns the server has been stopped and the program will
-   be terminated. */
+  /* Initialize random number generator for the server. */
+  server->rng = silc_rng_alloc();
+  silc_rng_init(server->rng);
+  silc_rng_global_init(server->rng);
 
-void silc_server_run(SilcServer server)
-{
-  SILC_LOG_INFO(("SILC Server started"));
+  /* Initialize hash functions for server to use */
+  silc_hash_alloc("md5", &server->md5hash);
+  silc_hash_alloc("sha1", &server->sha1hash);
 
-  /* Start the scheduler, the heart of the SILC server. When this returns
-     the program will be terminated. */
-  silc_schedule(server->schedule);
-}
+  /* Initialize the scheduler */
+  server->schedule = silc_schedule_init(server->config->param.connections_max,
+                                       server);
+  if (!server->schedule)
+    goto err;
 
-/* Stops the SILC server. This function is used to shutdown the server.
-   This is usually called after the scheduler has returned. After stopping
-   the server one should call silc_server_free. */
+  /* First, register log files configuration for error output */
+  silc_server_config_setlogfiles(server);
 
-void silc_server_stop(SilcServer server)
-{
-  SILC_LOG_INFO(("SILC Server shutting down"));
+  /* Initialize ID caches */
+  server->local_list->clients =
+    silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
+                      server);
+  server->local_list->servers =
+    silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL);
+  server->local_list->channels =
+    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+
+  /* These are allocated for normal server as well as these hold some
+     global information that the server has fetched from its router. For
+     router these are used as they are supposed to be used on router. */
+  server->global_list->clients =
+    silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
+                      server);
+  server->global_list->servers =
+    silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL);
+  server->global_list->channels =
+    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+
+  /* Init watcher lists */
+  server->watcher_list =
+    silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
+                         silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
+                         NULL, NULL, TRUE);
+  if (!server->watcher_list)
+    goto err;
+  server->watcher_list_pk =
+    silc_hash_table_alloc(1, silc_hash_public_key, NULL,
+                         silc_hash_public_key_compare, NULL,
+                         NULL, NULL, TRUE);
+  if (!server->watcher_list_pk)
+    goto err;
+
+  /* Init public key list */
+  server->pk_hash =
+    silc_hash_table_alloc(0, silc_hash_public_key, NULL,
+                          silc_hash_public_key_compare, NULL,
+                          NULL, NULL, TRUE);
 
-  if (server->schedule) {
-    int i;
+  if (!server->pk_hash)
+    goto err;
 
-    server->server_shutdown = TRUE;
+  /* Create TCP listener */
+  listener = 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);
+  if (!listener)
+    goto err;
 
-    /* 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])) {
-       SilcSocketConnection sock = server->sockets[i];
-       SilcIDListData idata = sock->user_data;
-
-       if (idata)
-         idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
-
-       silc_schedule_task_del_by_context(server->schedule,
-                                         server->sockets[i]);
-       silc_schedule_task_del_by_fd(server->schedule,
-                                    server->sockets[i]->sock);
-       silc_server_disconnect_remote(server, server->sockets[i],
-                                     SILC_STATUS_OK,
-                                     "Server is shutting down");
-       if (server->sockets[i]) {
-         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;
-        server->stat.conn_num--;
-      }
+  silc_dlist_add(server->listeners, listener);
+
+#if 0
+  /* Perform name and address lookups to resolve the listenning address
+     and port. */
+  if (!silc_net_check_local_by_sock(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);
+#endif
 
-    /* We are not connected to network anymore */
-    server->standalone = TRUE;
+  /* Create a Server ID for the server. */
+  port = silc_net_listener_get_port(listener, NULL);
+  ip = silc_net_listener_get_ip(listener, NULL);
+  silc_id_create_server_id(ip[0], port[0], server->rng, &id);
+  if (!id)
+    goto err;
 
-    silc_schedule_stop(server->schedule);
-    silc_schedule_uninit(server->schedule);
-    server->schedule = NULL;
+  silc_free(port);
+  silc_free(ip[0]);
+  silc_free(ip);
 
-    silc_free(server->sockets);
-    server->sockets = NULL;
+  server->id = id;
+  server->server_name = server->config->server_info->server_name;
+  server->config->server_info->server_name = NULL;
+
+  /* Add ourselves to the server list. We don't have a router yet
+     beacuse we haven't established a route yet. It will be done later.
+     For now, NULL is sent as router. This allocates new entry to
+     the ID list. */
+  id_entry =
+    silc_idlist_add_server(server->local_list, strdup(server->server_name),
+                          server->server_type, server->id, NULL, NULL);
+  if (!id_entry) {
+    SILC_LOG_ERROR(("Could not add ourselves to cache"));
+    goto err;
   }
+  id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+  server->id_entry = id_entry;
 
-  silc_server_protocols_unregister();
+  /* Create secondary TCP listeners */
+  if (silc_server_init_secondary(server) == FALSE)
+    goto err;
 
-  SILC_LOG_DEBUG(("Server stopped"));
-}
+  /* Create connections to configured routers. */
+  silc_server_create_connections(server);
 
-/* Function that is called when the network connection to a router has
-   been established.  This will continue with the key exchange protocol
-   with the remote router. */
+  server->listenning = TRUE;
 
-void silc_server_start_key_exchange(SilcServer server,
-                                   SilcServerConnection sconn,
-                                   int sock)
-{
-  SilcSocketConnection newsocket;
-  SilcProtocol protocol;
-  SilcServerKEInternalContext *proto_ctx;
-  SilcServerConfigRouter *conn =
-    (SilcServerConfigRouter *) sconn->conn.ref_ptr;
-  void *context;
+  /* Allocate the entire socket list that is used in server. Eventually
+     all connections will have entry in this table (it is a table of
+     pointers to the actual object that is allocated individually
+     later). */
+  server->sockets = silc_calloc(server->config->param.connections_max,
+                               sizeof(*server->sockets));
+  if (!server->sockets)
+    goto err;
 
-  /* Cancel any possible retry timeouts */
-  silc_schedule_task_del_by_callback(server->schedule,
-                                    silc_server_connect_to_router_retry);
-
-  /* Set socket options */
-  silc_net_set_socket_nonblock(sock);
-  silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
-  /* Create socket connection for the connection. Even though we
-     know that we are connecting to a router we will mark the socket
-     to be unknown connection until we have executed authentication
-     protocol. */
-  silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
-  server->sockets[sock] = newsocket;
-  newsocket->hostname = strdup(sconn->remote_host);
-  newsocket->ip = strdup(sconn->remote_host);
-  newsocket->port = sconn->remote_port;
-  sconn->sock = newsocket;
-
-  /* Allocate internal protocol context. This is sent as context
-     to the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->server = (void *)server;
-  proto_ctx->context = (void *)sconn;
-  proto_ctx->sock = newsocket;
-  proto_ctx->rng = server->rng;
-  proto_ctx->responder = FALSE;
+  /* If server connections has been configured then we must be router as
+     normal server cannot have server connections, only router connections. */
+  if (server->config->servers) {
+    SilcServerConfigServer *ptr = server->config->servers;
 
-  /* Set Key Exchange flags from configuration, but fall back to global
-     settings too. */
-  SILC_GET_SKE_FLAGS(conn, proto_ctx);
-  if (server->config->param.key_exchange_pfs)
-    proto_ctx->flags |= SILC_SKE_SP_FLAG_PFS;
-
-  /* Perform key exchange protocol. silc_server_connect_to_router_second
-     will be called after the protocol is finished. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
-                     &protocol, proto_ctx,
-                     silc_server_connect_to_router_second);
-  newsocket->protocol = protocol;
-
-  /* Register a timeout task that will be executed if the protocol
-     is not executed within set limit. */
-  proto_ctx->timeout_task =
-    silc_schedule_task_add(server->schedule, sock,
-                          silc_server_timeout_remote,
-                          server, server->config->key_exchange_timeout, 0,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW);
-
-  /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection
-     and sets that outgoing packets may be sent to this connection as
-     well. However, this doesn't set the scheduler for outgoing traffic,
-     it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
-     later when outgoing data is available. */
-  context = (void *)server;
-  SILC_REGISTER_CONNECTION_FOR_IO(sock);
-
-  /* Run the protocol */
-  silc_protocol_execute(protocol, server->schedule, 0, 0);
-}
+    server->server_type = SILC_ROUTER;
+    while (ptr) {
+      if (ptr->backup_router) {
+       server->server_type = SILC_BACKUP_ROUTER;
+       server->backup_router = TRUE;
+       server->id_entry->server_type = SILC_BACKUP_ROUTER;
+       break;
+      }
+      ptr = ptr->next;
+    }
+  }
 
-/* Timeout callback that will be called to retry connecting to remote
-   router. This is used by both normal and router server. This will wait
-   before retrying the connecting. The timeout is generated by exponential
-   backoff algorithm. */
+  /* Register the ID Cache purge task. This periodically purges the ID cache
+     and removes the expired cache entries. */
 
-SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
-{
-  SilcServer server = app_context;
-  SilcServerConnection sconn = (SilcServerConnection)context;
-  SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
-  SilcServerConfigConnParams *param =
-               (conn->param ? conn->param : &server->config->param);
+  /* Clients local list */
+  server->purge_i = purge = silc_calloc(1, sizeof(*purge));
+  purge->cache = server->local_list->clients;
+  purge->timeout = 600;
+  silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge,
+                                (void *)purge, purge->timeout, 0);
 
-  /* 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;
-  }
+  /* Clients global list */
+  server->purge_g = purge = silc_calloc(1, sizeof(*purge));
+  purge->cache = server->global_list->clients;
+  purge->timeout = 300;
+  silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge,
+                                (void *)purge, purge->timeout, 0);
 
-  SILC_LOG_INFO(("Retrying connecting to a router"));
+  /* If we are normal server we'll retrieve network statisticial information
+     once in a while from the router. */
+  if (server->server_type != SILC_ROUTER)
+    silc_schedule_task_add_timeout(server->schedule, silc_server_get_stats,
+                                  server, 10, 0);
 
-  /* Calculate next timeout */
-  if (sconn->retry_count >= 1) {
-    sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
-    if (sconn->retry_timeout > param->reconnect_interval_max)
-      sconn->retry_timeout = param->reconnect_interval_max;
-  } else {
-    sconn->retry_timeout = param->reconnect_interval;
-  }
-  sconn->retry_count++;
-  sconn->retry_timeout = sconn->retry_timeout +
-    (silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER);
+  if (server->server_type == SILC_ROUTER)
+    server->stat.routers++;
 
-  /* If we've reached max retry count, give up. */
-  if ((sconn->retry_count > param->reconnect_count) &&
-      !param->reconnect_keep_trying) {
-    SILC_LOG_ERROR(("Could not connect to router, giving up"));
-    silc_server_config_unref(&sconn->conn);
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
-    return;
-  }
+  /* Start packet engine */
+  server->packet_engine =
+    silc_packet_engine_start(server->rng, server->server_type == SILC_ROUTER,
+                            &silc_server_stream_cbs, server);
+  if (!server->packet_engine)
+    goto err;
 
-  SILC_LOG_DEBUG(("Retrying connecting to a router in %d seconds",
-                 sconn->retry_timeout));
+  SILC_LOG_DEBUG(("Server initialized"));
 
-  /* We will lookup a fresh pointer later */
-  silc_server_config_unref(&sconn->conn);
+  /* We are done here, return succesfully */
+  return TRUE;
 
-  /* Wait one before retrying */
-  silc_schedule_task_add(server->schedule, 0, silc_server_connect_router,
-                        context, sconn->retry_timeout, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ err:
+  silc_server_config_unref(&server->config_ref);
+  return FALSE;
 }
 
-/* Callback for async connection to remote router */
+#if 0
+/* Task callback to close a socket connection after rehash */
 
-SILC_TASK_CALLBACK(silc_server_connection_established)
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
 {
-  SilcServer server = app_context;
-  SilcServerConnection sconn = (SilcServerConnection)context;
-  int sock = fd;
-  int opt = EINVAL, optlen = sizeof(opt), ret;
-
-  ret = silc_net_get_socket_opt(sock, SOL_SOCKET, SO_ERROR, &opt, &optlen);
-
-  silc_schedule_task_del_by_fd(server->schedule, sock);
-  silc_schedule_unset_listen_fd(server->schedule, sock);
+  SilcServer server = context;
+  SilcPacketStream sock = server->sockets[fd];
 
-  if (ret != 0 || opt != 0) {
-    SILC_LOG_ERROR(("Could not connect to router %s:%d: %s",
-                   sconn->remote_host, sconn->remote_port, strerror(opt)));
-    silc_net_close_connection(sock);
-    if (!sconn->no_reconnect) {
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_connect_to_router_retry,
-                            context, 1, 0, SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-    } else {
-      silc_server_config_unref(&sconn->conn);
-      silc_free(sconn->remote_host);
-      silc_free(sconn->backup_replace_ip);
-      silc_free(sconn);
-    }
+  if (!sock)
     return;
-  }
-
-  SILC_LOG_DEBUG(("Connection to router %s:%d established", sconn->remote_host,
-                sconn->remote_port));
 
-  /* Continue with key exchange protocol */
-  silc_server_start_key_exchange(server, sconn, sock);
+  SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured",
+                sock->hostname, sock->port,
+                (sock->type == SILC_CONN_UNKNOWN ? "Unknown" :
+                 sock->type == SILC_CONN_CLIENT ? "Client" :
+                 sock->type == SILC_CONN_SERVER ? "Server" :
+                 "Router")));
+  silc_schedule_task_del_by_context(server->schedule, sock);
+  silc_server_disconnect_remote(server, sock,
+                               SILC_STATUS_ERR_BANNED_FROM_SERVER,
+                               "This connection is removed from "
+                               "configuration");
+  if (sock->user_data)
+    silc_server_free_sock_user_data(server, sock, NULL);
 }
+#endif /* 0 */
 
-/* Generic routine to use connect to a router. */
+/* This function basically reads the config file again and switches the config
+   object pointed by the server object. After that, we have to fix various
+   things such as the server_name and the listening ports.
+   Keep in mind that we no longer have the root privileges at this point. */
 
-SILC_TASK_CALLBACK(silc_server_connect_router)
+SilcBool silc_server_rehash(SilcServer server)
 {
-  SilcServer server = app_context;
-  SilcServerConnection sconn = (SilcServerConnection)context;
-  SilcServerConfigRouter *rconn;
-  int sock;
+#if 0
+  SilcServerConfig newconfig;
 
-  /* 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(("Rehashing server"));
 
-  SILC_LOG_INFO(("Connecting to the %s %s on port %d",
-                (sconn->backup ? "backup router" : "router"),
-                sconn->remote_host, sconn->remote_port));
+  /* Reset the logging system */
+  silc_log_quick(TRUE);
+  silc_log_flush_all();
 
-  server->router_connect = time(NULL);
-  rconn = silc_server_config_find_router_conn(server, sconn->remote_host,
-                                             sconn->remote_port);
-  if (!rconn) {
-    SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
-                  (sconn->backup ? "backup router" : "router"),
-                  sconn->remote_host, sconn->remote_port));
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
-    return;
+  /* Start the main rehash phase (read again the config file) */
+  newconfig = silc_server_config_alloc(server->config_file, server);
+  if (!newconfig) {
+    SILC_LOG_ERROR(("Rehash FAILED."));
+    return FALSE;
   }
-  silc_server_config_ref(&sconn->conn, server->config, (void *)rconn);
 
-  /* Connect to remote host */
-  sock = silc_net_create_connection_async(
-                (!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));
-    if (!sconn->no_reconnect) {
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_connect_to_router_retry,
-                            context, 1, 0, SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-    } else {
-      silc_server_config_unref(&sconn->conn);
-      silc_free(sconn->remote_host);
-      silc_free(sconn->backup_replace_ip);
-      silc_free(sconn);
-    }
-    return;
-  }
+  /* Reinit scheduler if necessary */
+  if (newconfig->param.connections_max > server->config->param.connections_max)
+    if (!silc_schedule_reinit(server->schedule,
+                             newconfig->param.connections_max))
+      return FALSE;
 
-  /* wait for the connection to be established */
-  silc_schedule_task_add(server->schedule, sock,
-                        silc_server_connection_established,
-                        context, 0, 0, SILC_TASK_FD,
-                        SILC_TASK_PRI_NORMAL);
-  silc_schedule_set_listen_fd(server->schedule, sock,
-                             SILC_TASK_WRITE, FALSE);
-}
+  /* Fix the server_name field */
+  if (strcmp(server->server_name, newconfig->server_info->server_name)) {
+    silc_free(server->server_name);
 
-/* This function connects to our primary router or if we are a router this
-   establishes all our primary routes. This is called at the start of the
-   server to do authentication and key exchange with our router - called
-   from schedule. */
+    /* Check server name */
+    server->server_name =
+      silc_identifier_check(newconfig->server_info->server_name,
+                           strlen(newconfig->server_info->server_name),
+                           SILC_STRING_LOCALE, 256, NULL);
+    if (!server->server_name) {
+      SILC_LOG_ERROR(("Malformed server name string '%s'",
+                     server->config->server_info->server_name));
+      return FALSE;
+    }
 
-SILC_TASK_CALLBACK_GLOBAL(silc_server_connect_to_router)
-{
-  SilcServer server = (SilcServer)context;
-  SilcServerConnection sconn;
-  SilcServerConfigRouter *ptr;
+    /* Update the idcache list with a fresh pointer */
+    silc_free(server->id_entry->server_name);
+    server->id_entry->server_name = strdup(server->server_name);
+    if (!silc_idcache_del_by_context(server->local_list->servers,
+                                    server->id_entry))
+      return FALSE;
+    if (!silc_idcache_add(server->local_list->servers,
+                         strdup(server->id_entry->server_name),
+                         server->id_entry->id, server->id_entry, 0, NULL))
+      return FALSE;
+  }
 
-  /* Don't connect if we are shutting down. */
-  if (server->server_shutdown)
-    return;
+  /* Set logging */
+  silc_server_config_setlogfiles(server);
 
-  SILC_LOG_DEBUG(("We are %s",
-                 (server->server_type == SILC_SERVER ?
-                  "normal server" : server->server_type == SILC_ROUTER ?
-                  "router" : "backup router/normal server")));
+  /* Change new key pair if necessary */
+  if (newconfig->server_info->public_key &&
+      !silc_pkcs_public_key_compare(server->public_key,
+                                   newconfig->server_info->public_key)) {
+    silc_pkcs_public_key_free(server->public_key);
+    silc_pkcs_private_key_free(server->private_key);
+    server->public_key = newconfig->server_info->public_key;
+    server->private_key = newconfig->server_info->private_key;
+    newconfig->server_info->public_key = NULL;
+    newconfig->server_info->private_key = NULL;
 
-  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), we are standalone"));
-    server->standalone = TRUE;
-    return;
+    /* Allocate PKCS context for local public and private keys */
+    silc_pkcs_free(server->pkcs);
+    if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
+      return FALSE;
+    silc_pkcs_public_key_set(server->pkcs, server->public_key);
+    silc_pkcs_private_key_set(server->pkcs, server->private_key);
   }
 
-  /* Cancel any possible retry timeouts */
-  silc_schedule_task_del_by_callback(server->schedule,
-                                    silc_server_connect_router);
-  silc_schedule_task_del_by_callback(server->schedule,
-                                    silc_server_connect_to_router_retry);
-
-  /* Create the connections to all our routes */
-  for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+  /* Check for unconfigured server and router connections and close
+     connections that were unconfigured. */
 
-    SILC_LOG_DEBUG(("%s connection [%s] %s:%d",
-                   ptr->backup_router ? "Backup router" : "Router",
-                   ptr->initiator ? "Initiator" : "Responder",
-                   ptr->host, ptr->port));
+  if (server->config->routers) {
+    SilcServerConfigRouter *ptr;
+    SilcServerConfigRouter *newptr;
+    SilcBool found;
 
-    if (server->server_type == SILC_ROUTER && ptr->backup_router &&
-       ptr->initiator == FALSE && !server->backup_router &&
-       !silc_server_config_get_backup_router(server))
-      server->wait_backup = TRUE;
+    for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+      found = FALSE;
 
-    if (ptr->initiator) {
-      /* Check whether we are connecting or connected to this host already */
-      if (silc_server_num_sockets_by_remote(server,
-                                           silc_net_is_ip(ptr->host) ?
-                                           ptr->host : NULL,
-                                           silc_net_is_ip(ptr->host) ?
-                                           NULL : ptr->host, ptr->port,
-                                           SILC_SOCKET_TYPE_ROUTER)) {
-       SILC_LOG_DEBUG(("We are already connected to this router"));
-
-       /* If we don't have primary router and this connection is our
-          primary router we are in desync.  Reconnect to the primary. */
-       if (server->standalone && !server->router) {
-         SilcServerConfigRouter *primary =
-           silc_server_config_get_primary_router(server);
-         if (primary == ptr) {
-           SilcSocketConnection sock =
-             silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
-                                             ptr->host, ptr->port);
-           if (sock) {
-             server->backup_noswitch = TRUE;
-             if (sock->user_data)
-               silc_server_free_sock_user_data(server, sock, NULL);
-             silc_server_disconnect_remote(server, sock, 0, NULL);
-             server->backup_noswitch = FALSE;
-             SILC_LOG_DEBUG(("Reconnecting to primary router"));
-           } else {
-             continue;
-           }
-         } else {
-           continue;
-         }
-       } else {
-         continue;
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
+       if (silc_string_compare(newptr->host, ptr->host) &&
+           newptr->port == ptr->port &&
+           newptr->initiator == ptr->initiator) {
+         found = TRUE;
+         break;
        }
       }
-      if (silc_server_num_sockets_by_remote(server,
-                                           silc_net_is_ip(ptr->host) ?
-                                           ptr->host : NULL,
-                                           silc_net_is_ip(ptr->host) ?
-                                           NULL : ptr->host, ptr->port,
-                                           SILC_SOCKET_TYPE_UNKNOWN)) {
-       SILC_LOG_DEBUG(("We are already connecting to this router"));
-       continue;
-      }
 
-      /* Allocate connection object for hold connection specific stuff. */
-      sconn = silc_calloc(1, sizeof(*sconn));
-      sconn->remote_host = strdup(ptr->host);
-      sconn->remote_port = ptr->port;
-      sconn->backup = ptr->backup_router;
-      if (sconn->backup) {
-       sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
-       sconn->backup_replace_port = ptr->backup_replace_port;
+      if (!found && ptr->host) {
+       /* Remove this connection */
+       SilcPacketStream sock;
+       sock = silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+                                              ptr->host, ptr->port);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
       }
-
-      if (!server->router_conn && !sconn->backup)
-       server->router_conn = sconn;
-
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_connect_router,
-                            (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
     }
   }
-}
 
-/* Second part of connecting to router(s). Key exchange protocol has been
-   executed and now we will execute authentication protocol. */
-
-SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx =
-    (SilcServerKEInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-  SilcServerConnection sconn = (SilcServerConnection)ctx->context;
-  SilcSocketConnection sock = ctx->sock;
-  SilcServerConnAuthInternalContext *proto_ctx;
-  SilcServerConfigRouter *conn = NULL;
+  if (server->config->servers) {
+    SilcServerConfigServer *ptr;
+    SilcServerConfigServer *newptr;
+    SilcBool found;
 
-  SILC_LOG_DEBUG(("Start"));
+    for (ptr = server->config->servers; ptr; ptr = ptr->next) {
+      found = FALSE;
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-    /* Error occured during protocol */
-    silc_protocol_free(protocol);
-    sock->protocol = NULL;
-    silc_ske_free_key_material(ctx->keymat);
-    if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx->dest_id);
-    silc_free(ctx);
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
+       if (silc_string_compare(newptr->host, ptr->host)) {
+         found = TRUE;
+         break;
+       }
+      }
 
-    /* Try reconnecting if configuration wants it */
-    if (!sconn->no_reconnect) {
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_connect_to_router_retry,
-                            sconn, 1, 0, SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-      return;
+      if (!found && ptr->host) {
+       /* Remove this connection */
+       SilcPacketStream sock;
+       sock = silc_server_find_socket_by_host(server, SILC_CONN_SERVER,
+                                              ptr->host, 0);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
     }
-
-    /* Call completion to indicate error */
-    if (sconn->callback)
-      (*sconn->callback)(server, NULL, sconn->callback_context);
-
-    silc_server_config_unref(&sconn->conn);
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
-    return;
   }
 
-  /* We now have the key material as the result of the key exchange
-     protocol. Take the key material into use. Free the raw key material
-     as soon as we've set them into use. */
-  if (!silc_server_protocol_ke_set_keys(server, ctx->ske,
-                                       ctx->sock, ctx->keymat,
-                                       ctx->ske->prop->cipher,
-                                       ctx->ske->prop->pkcs,
-                                       ctx->ske->prop->hash,
-                                       ctx->ske->prop->hmac,
-                                       ctx->ske->prop->group,
-                                       ctx->responder)) {
-    silc_protocol_free(protocol);
-    sock->protocol = NULL;
-    silc_ske_free_key_material(ctx->keymat);
-    if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx->dest_id);
-    silc_free(ctx);
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
-
-    /* Try reconnecting if configuration wants it */
-    if (!sconn->no_reconnect) {
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_connect_to_router_retry,
-                            sconn, 1, 0, SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-      return;
-    }
+  if (server->config->clients) {
+    SilcServerConfigClient *ptr;
+    SilcServerConfigClient *newptr;
+    SilcBool found;
 
-    /* Call completion to indicate error */
-    if (sconn->callback)
-      (*sconn->callback)(server, NULL, sconn->callback_context);
+    for (ptr = server->config->clients; ptr; ptr = ptr->next) {
+      found = FALSE;
 
-    silc_server_config_unref(&sconn->conn);
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
-    return;
-  }
-  silc_ske_free_key_material(ctx->keymat);
-
-  /* Allocate internal context for the authentication protocol. This
-     is sent as context for the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->server = (void *)server;
-  proto_ctx->context = (void *)sconn;
-  proto_ctx->sock = sock;
-  proto_ctx->ske = ctx->ske;      /* Save SKE object from previous protocol */
-  proto_ctx->dest_id_type = ctx->dest_id_type;
-  proto_ctx->dest_id = ctx->dest_id;
-
-  /* Resolve the authentication method used in this connection. Check if
-     we find a match from user configured connections */
-  if (!sconn->conn.ref_ptr)
-    conn = silc_server_config_find_router_conn(server, sock->hostname,
-                                              sock->port);
-  else
-    conn = sconn->conn.ref_ptr;
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->clients; newptr; newptr = newptr->next) {
+       if (silc_string_compare(newptr->host, ptr->host)) {
+         found = TRUE;
+         break;
+       }
+      }
 
-  if (conn) {
-    /* Match found. Use the configured authentication method. Take only
-       the passphrase, since for public key auth we automatically use
-       our local key pair. */
-    if (conn->passphrase) {
-      if (conn->publickeys && !server->config->prefer_passphrase_auth) {
-       proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
-      } else {
-       proto_ctx->auth_data = strdup(conn->passphrase);
-       proto_ctx->auth_data_len = strlen(conn->passphrase);
-       proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
+      if (!found && ptr->host) {
+       /* Remove this connection */
+       SilcPacketStream sock;
+       sock = silc_server_find_socket_by_host(server, SILC_CONN_CLIENT,
+                                              ptr->host, 0);
+       if (sock)
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
       }
-    } else if (conn->publickeys) {
-      proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
-    } else {
-      proto_ctx->auth_meth = SILC_AUTH_NONE;
     }
-  } else {
-    SILC_LOG_ERROR(("Could not find connection data for %s (%s) on port",
-                   sock->hostname, sock->ip, sock->port));
-    silc_protocol_free(protocol);
-    sock->protocol = NULL;
-    if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx->dest_id);
-    silc_free(ctx);
-    silc_server_config_unref(&sconn->conn);
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
-    return;
   }
 
-  /* Free old protocol as it is finished now */
-  silc_protocol_free(protocol);
-  if (ctx->packet)
-    silc_packet_context_free(ctx->packet);
-  silc_free(ctx);
-  sock->protocol = NULL;
-
-  /* Allocate the authentication protocol. This is allocated here
-     but we won't start it yet. We will be receiving party of this
-     protocol thus we will wait that connecting party will make
-     their first move. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
-                     &sock->protocol, proto_ctx,
-                     silc_server_connect_to_router_final);
-
-  /* Register timeout task. If the protocol is not executed inside
-     this timelimit the connection will be terminated. */
-  proto_ctx->timeout_task =
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_timeout_remote,
-                          (void *)server,
-                          server->config->conn_auth_timeout, 0,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW);
-
-  /* Run the protocol */
-  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-}
-
-/* Finalizes the connection to router. Registers a server task to the
-   queue so that we can accept new connections. */
-
-SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerConnAuthInternalContext *ctx =
-    (SilcServerConnAuthInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-  SilcServerConnection sconn = (SilcServerConnection)ctx->context;
-  SilcSocketConnection sock = ctx->sock;
-  SilcServerEntry id_entry = NULL;
-  SilcBuffer packet;
-  unsigned char *id_string;
-  SilcUInt32 id_len;
-  SilcIDListData idata;
-  SilcServerConfigRouter *conn = NULL;
-  SilcServerConfigConnParams *param = NULL;
-
-  SILC_LOG_DEBUG(("Start"));
+  /* Create connections after rehash */
+  silc_server_create_connections(server);
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-    /* Error occured during protocol */
-    silc_free(ctx->dest_id);
-    sock->protocol = NULL;
-    silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
-                                 NULL);
-    sock->protocol = protocol;
+  /* Check whether our router status has changed */
+  if (newconfig->servers) {
+    SilcServerConfigServer *ptr = newconfig->servers;
 
-    /* Try reconnecting if configuration wants it */
-    if (!sconn->no_reconnect) {
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_connect_to_router_retry,
-                            sconn, 1, 0, SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-      goto out2;
+    server->server_type = SILC_ROUTER;
+    while (ptr) {
+      if (ptr->backup_router) {
+       server->server_type = SILC_BACKUP_ROUTER;
+       server->backup_router = TRUE;
+       server->id_entry->server_type = SILC_BACKUP_ROUTER;
+       break;
+      }
+      ptr = ptr->next;
     }
-
-    goto out;
   }
 
-  /* 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 && !sconn->backup) {
-    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;
-  }
-
-  /* Send NEW_SERVER packet to the router. We will become registered
-     to the SILC network after sending this packet. */
-  id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
-  id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
-  packet = silc_buffer_alloc(2 + 2 + id_len + strlen(server->server_name));
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(id_len),
-                    SILC_STR_UI_XNSTRING(id_string, id_len),
-                    SILC_STR_UI_SHORT(strlen(server->server_name)),
-                    SILC_STR_UI_XNSTRING(server->server_name,
-                                         strlen(server->server_name)),
-                    SILC_STR_END);
-
-  /* Send the packet */
-  silc_server_packet_send(server, ctx->sock, SILC_PACKET_NEW_SERVER, 0,
-                         packet->data, packet->len, TRUE);
-  silc_buffer_free(packet);
-  silc_free(id_string);
-
-  SILC_LOG_INFO(("Connected to router %s", sock->hostname));
-
-  /* Check that we do not have this ID already */
-  id_entry = silc_idlist_find_server_by_id(server->local_list,
-                                          ctx->dest_id, TRUE, NULL);
-  if (id_entry) {
-    silc_idcache_del_by_context(server->local_list->servers, id_entry);
-  } else {
-    id_entry = silc_idlist_find_server_by_id(server->global_list,
-                                            ctx->dest_id, TRUE, NULL);
-    if (id_entry)
-      silc_idcache_del_by_context(server->global_list->servers, id_entry);
-  }
+  /* Our old config is gone now. We'll unreference our reference made in
+     silc_server_init and then destroy it since we are destroying it
+     underneath the application (layer which called silc_server_init). */
+  silc_server_config_unref(&server->config_ref);
+  silc_server_config_destroy(server->config);
 
-  SILC_LOG_DEBUG(("New server id(%s)",
-                 silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
+  /* Take new config context */
+  server->config = newconfig;
+  silc_server_config_ref(&server->config_ref, server->config, server->config);
 
-  /* 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);
-  if (!id_entry) {
-    silc_free(ctx->dest_id);
-    SILC_LOG_ERROR(("Cannot add new server entry to cache"));
-    sock->protocol = NULL;
-    silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
-                                 NULL);
-    sock->protocol = protocol;
-    goto out;
+#ifdef SILC_DEBUG
+  /* Set debugging on if configured */
+  if (server->config->debug_string) {
+    silc_log_debug(TRUE);
+    silc_log_set_debug_string(server->config->debug_string);
   }
+#endif /* SILC_DEBUG */
 
-  silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
-  silc_free(sock->user_data);
-  sock->user_data = (void *)id_entry;
-  sock->type = SILC_SOCKET_TYPE_ROUTER;
-  idata = (SilcIDListData)sock->user_data;
-  idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
-                   SILC_IDLIST_STATUS_LOCAL);
-
-  conn = sconn->conn.ref_ptr;
-  param = &server->config->param;
-  if (conn && conn->param)
-    param = conn->param;
-
-  /* Perform keepalive. */
-  silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
-                           silc_server_perform_heartbeat,
-                           server->schedule);
-
-  /* Register re-key timeout */
-  idata->rekey->timeout = param->key_exchange_rekey;
-  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);
-
-  if (!sconn->backup) {
-    /* Mark this router our primary router if we're still standalone */
-    if (server->standalone) {
-      SILC_LOG_DEBUG(("This connection is our primary router"));
-      server->id_entry->router = id_entry;
-      server->router = id_entry;
-      server->router->server_type = SILC_ROUTER;
-      server->standalone = FALSE;
-      server->backup_primary = FALSE;
-
-      /* Announce data if we are not backup router (unless not as primary
-        currently).  Backup router announces later at the end of
-        resuming protocol. */
-      if (server->backup_router && server->server_type == SILC_ROUTER) {
-       SILC_LOG_DEBUG(("Announce data after resume protocol"));
-      } else {
-       /* 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,
-                                      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));
-       silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
-      }
-
-      /* 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,
-                              sconn->remote_port, TRUE);
-    }
-  } else {
-    /* Add this server to be our backup router */
-    id_entry->server_type = SILC_BACKUP_ROUTER;
-    silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
-                          sconn->backup_replace_port, FALSE);
-  }
+  SILC_LOG_DEBUG(("Server rehashed"));
+#endif /* 0 */
 
-  sock->protocol = NULL;
+  return TRUE;
+}
 
- out:
-  /* Call the completion callback to indicate that we've connected to
-     the router */
-  if (sconn && sconn->callback)
-    (*sconn->callback)(server, id_entry, sconn->callback_context);
+/* The heart of the server. This runs the scheduler thus runs the server.
+   When this returns the server has been stopped and the program will
+   be terminated. */
 
-  /* Free the temporary connection data context */
-  if (sconn) {
-    silc_server_config_unref(&sconn->conn);
-    silc_free(sconn->remote_host);
-    silc_free(sconn->backup_replace_ip);
-    silc_free(sconn);
-  }
-  if (sconn == server->router_conn)
-    server->router_conn = NULL;
+void silc_server_run(SilcServer server)
+{
+  SILC_LOG_INFO(("SILC Server started"));
 
- out2:
-  /* Free the protocol object */
-  if (sock->protocol == protocol)
-    sock->protocol = NULL;
-  silc_protocol_free(protocol);
-  if (ctx->packet)
-    silc_packet_context_free(ctx->packet);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
-  if (ctx->auth_meth == SILC_AUTH_PASSWORD)
-    silc_free(ctx->auth_data);
-  silc_free(ctx);
+  /* Start the scheduler, the heart of the SILC server. When this returns
+     the program will be terminated. */
+  silc_schedule(server->schedule);
 }
 
-/* Host lookup callback that is called after the incoming connection's
-   IP and FQDN lookup is performed. This will actually check the acceptance
-   of the incoming connection and will register the key exchange protocol
-   for this connection. */
-
-static void
-silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
-                                        void *context)
+/* Stops the SILC server. This function is used to shutdown the server.
+   This is usually called after the scheduler has returned. After stopping
+   the server one should call silc_server_free. */
+
+void silc_server_stop(SilcServer server)
 {
-  SilcServerKEInternalContext *proto_ctx =
-    (SilcServerKEInternalContext *)context;
-  SilcServer server = (SilcServer)proto_ctx->server;
-  SilcServerConfigClient *cconfig = NULL;
-  SilcServerConfigServer *sconfig = NULL;
-  SilcServerConfigRouter *rconfig = NULL;
-  SilcServerConfigDeny *deny;
-  int port;
-
-  /* Check whether we could resolve both IP and FQDN. */
-  if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
-                   server->config->require_reverse_lookup)) {
-    SILC_LOG_ERROR(("IP/DNS lookup failed %s",
-                   sock->hostname ? sock->hostname :
-                   sock->ip ? sock->ip : ""));
-    server->stat.conn_failures++;
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
-                                 "Unknown host or IP");
-    silc_free(proto_ctx);
-    return;
-  }
+  SilcDList list;
+  SilcPacketStream ps;
 
-  /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection
-     and sets that outgoing packets may be sent to this connection as well.
-     However, this doesn't set the scheduler for outgoing traffic, it
-     will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
-     later when outgoing data is available. */
-  context = (void *)server;
-  SILC_REGISTER_CONNECTION_FOR_IO(sock->sock);
+  SILC_LOG_INFO(("SILC Server shutting down"));
 
-  SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname,
-                sock->ip));
+  server->server_shutdown = TRUE;
 
-  /* Listenning port */
-  if (!server->sockets[SILC_PTR_TO_32(proto_ctx->context)]) {
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_RESOURCE_LIMIT,
-                                 "Connection refused");
-    server->stat.conn_failures++;
-    silc_free(proto_ctx);
-    return;
-  }
-  port = server->sockets[SILC_PTR_TO_32(proto_ctx->context)]->port;
+  /* Close all connections */
+  if (server->packet_engine) {
+    list = silc_packet_engine_get_streams(server->packet_engine);
 
-  /* Check whether this connection is denied to connect to us. */
-  deny = silc_server_config_find_denied(server, sock->ip);
-  if (!deny)
-    deny = silc_server_config_find_denied(server, sock->hostname);
-  if (deny) {
-    /* The connection is denied */
-    SILC_LOG_INFO(("Connection %s (%s) is denied",
-                  sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_BANNED_FROM_SERVER,
-                                 deny->reason);
-    server->stat.conn_failures++;
-    silc_free(proto_ctx);
-    return;
-  }
+    silc_dlist_start(list);
+    while ((ps = silc_dlist_get(list))) {
+      SilcIDListData idata = silc_packet_get_context(ps);
 
-  /* Check whether we have configured this sort of connection at all. We
-     have to check all configurations since we don't know what type of
-     connection this is. */
-  if (!(cconfig = silc_server_config_find_client(server, sock->ip)))
-    cconfig = silc_server_config_find_client(server, sock->hostname);
-  if (!(sconfig = silc_server_config_find_server_conn(server, sock->ip)))
-    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, sock->port)))
-      rconfig = silc_server_config_find_router_conn(server, sock->hostname,
-                                                   sock->port);
-  }
-  if (!cconfig && !sconfig && !rconfig) {
-    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, NULL);
-    server->stat.conn_failures++;
-    silc_free(proto_ctx);
-    return;
-  }
+      if (idata)
+       idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
 
-  /* The connection is allowed */
+      silc_server_disconnect_remote(server, ps, SILC_STATUS_OK,
+                                   "Server is shutting down");
+      silc_server_free_sock_user_data(server, ps,
+                                     "Server is shutting down");
+    }
+  }
 
-  /* Set internal context for key exchange protocol. This is
-     sent as context for the protocol. */
-  proto_ctx->sock = sock;
-  proto_ctx->rng = server->rng;
-  proto_ctx->responder = TRUE;
-  silc_server_config_ref(&proto_ctx->cconfig, server->config, cconfig);
-  silc_server_config_ref(&proto_ctx->sconfig, server->config, sconfig);
-  silc_server_config_ref(&proto_ctx->rconfig, server->config, rconfig);
+  /* We are not connected to network anymore */
+  server->standalone = TRUE;
 
-  /* Take flags for key exchange. Since we do not know what type of connection
-     this is, we go through all found configurations and use the global ones
-     as well. This will result always into strictest key exchange flags. */
-  SILC_GET_SKE_FLAGS(cconfig, proto_ctx);
-  SILC_GET_SKE_FLAGS(sconfig, proto_ctx);
-  SILC_GET_SKE_FLAGS(rconfig, proto_ctx);
-  if (server->config->param.key_exchange_pfs)
-    proto_ctx->flags |= SILC_SKE_SP_FLAG_PFS;
+  silc_schedule_stop(server->schedule);
+  silc_schedule_uninit(server->schedule);
+  server->schedule = NULL;
 
-  /* Prepare the connection for key exchange protocol. We allocate the
-     protocol but will not start it yet. The connector will be the
-     initiator of the protocol thus we will wait for initiation from
-     there before we start the protocol. */
-  server->stat.auth_attempts++;
-  SILC_LOG_DEBUG(("Starting key exchange protocol"));
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
-                     &sock->protocol, proto_ctx,
-                     silc_server_accept_new_connection_second);
-
-  /* Register a timeout task that will be executed if the connector
-     will not start the key exchange protocol within specified timeout
-     and the connection will be closed. */
-  proto_ctx->timeout_task =
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_timeout_remote,
-                          (void *)server,
-                          server->config->key_exchange_timeout, 0,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW);
+  SILC_LOG_DEBUG(("Server stopped"));
 }
 
-/* Accepts new connections to the server. Accepting new connections are
-   done in three parts to make it async. */
+#if 0
+/* Parses whole packet, received earlier. */
 
-SILC_TASK_CALLBACK(silc_server_accept_new_connection)
+SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 {
-  SilcServer server = (SilcServer)context;
-  SilcSocketConnection newsocket;
-  SilcServerKEInternalContext *proto_ctx;
-  int sock;
+  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
+  SilcServer server = (SilcServer)parse_ctx->context;
+  SilcPacketStream sock = parse_ctx->sock;
+  SilcPacket *packet = parse_ctx->packet;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
+  int ret;
 
-  SILC_LOG_DEBUG(("Accepting new connection"));
+  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+    SILC_LOG_DEBUG(("Connection is disconnected"));
+    goto out;
+  }
 
-  server->stat.conn_attempts++;
+  server->stat.packets_received++;
 
-  sock = silc_net_accept_connection(fd);
-  if (sock < 0) {
-    SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
-    server->stat.conn_failures++;
-    return;
+  /* Parse the packet */
+  if (parse_ctx->normal)
+    ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
+  else
+    ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
+
+  /* If entry is disabled ignore what we got. */
+  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 &&
+      ret != SILC_PACKET_KEY_EXCHANGE_1 && ret != SILC_PACKET_KEY_EXCHANGE_2) {
+    SILC_LOG_DEBUG(("Connection is disabled (packet %s dropped)",
+                   silc_get_packet_name(ret)));
+    goto out;
   }
 
-  /* Check for maximum allowed connections */
-  if (sock > server->config->param.connections_max) {
-    SILC_LOG_ERROR(("Refusing connection, server is full"));
-    server->stat.conn_failures++;
-    silc_net_close_connection(sock);
-    return;
+  if (ret == SILC_PACKET_NONE) {
+    SILC_LOG_DEBUG(("Error parsing packet"));
+    goto out;
   }
-  server->stat.conn_num++;
 
-  /* Set socket options */
-  silc_net_set_socket_nonblock(sock);
-  silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
-  /* We don't create a ID yet, since we don't know what type of connection
-     this is yet. But, we do add the connection to the socket table. */
-  silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
-  server->sockets[sock] = newsocket;
-
-  /* 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 = SILC_32_TO_PTR(fd);
-  silc_socket_host_lookup(newsocket, TRUE,
-                         silc_server_accept_new_connection_lookup,
-                         (void *)proto_ctx, server->schedule);
-}
+  /* Check that the the current client ID is same as in the client's packet. */
+  if (sock->type == SILC_CONN_CLIENT) {
+    SilcClientEntry client = (SilcClientEntry)sock->user_data;
+    if (client && client->id && packet->src_id) {
+      void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
+                               packet->src_id_type);
+      if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
+       silc_free(id);
+       SILC_LOG_DEBUG(("Packet source is not same as sender"));
+       goto out;
+      }
+      silc_free(id);
+    }
+  }
 
-/* Second part of accepting new connection. Key exchange protocol has been
-   performed and now it is time to do little connection authentication
-   protocol to figure out whether this connection is client or server
-   and whether it has right to access this server (especially server
-   connections needs to be authenticated). */
+  if (server->server_type == SILC_ROUTER) {
+    /* Route the packet if it is not destined to us. Other ID types but
+       server are handled separately after processing them. */
+    if (packet->dst_id && !(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
+       packet->dst_id_type == SILC_ID_SERVER &&
+       sock->type != SILC_CONN_CLIENT &&
+       memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
+      SilcPacketStream conn;
 
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx =
-    (SilcServerKEInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-  SilcSocketConnection sock = ctx->sock;
-  SilcServerConnAuthInternalContext *proto_ctx;
+      /* Route the packet to fastest route for the destination ID */
+      void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               packet->dst_id_type);
+      if (!id)
+       goto out;
 
-  SILC_LOG_DEBUG(("Start"));
+      conn = silc_server_route_get(server, id, packet->dst_id_type);
+      if (!conn) {
+       SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
+                         silc_id_render(id, SILC_ID_SERVER)));
+       goto out;
+      }
 
-  if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) ||
-      (protocol->state == SILC_PROTOCOL_STATE_FAILURE)) {
-    /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error in key exchange protocol"));
-    silc_protocol_free(protocol);
-    sock->protocol = NULL;
-    silc_ske_free_key_material(ctx->keymat);
-    if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx->dest_id);
-    silc_server_config_unref(&ctx->cconfig);
-    silc_server_config_unref(&ctx->sconfig);
-    silc_server_config_unref(&ctx->rconfig);
-    silc_free(ctx);
-
-    if (!SILC_IS_DISCONNECTING(sock)) {
-      SILC_LOG_INFO(("Key exchange failed for %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")));
-      silc_server_disconnect_remote(server, sock,
-                                   SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
-                                   NULL);
+      silc_server_packet_route(server, conn, packet);
+      silc_free(id);
+      goto out;
     }
-
-    server->stat.auth_failures++;
-    return;
   }
 
-  /* We now have the key material as the result of the key exchange
-     protocol. Take the key material into use. Free the raw key material
-     as soon as we've set them into use. */
-  if (!silc_server_protocol_ke_set_keys(server, ctx->ske,
-                                       ctx->sock, ctx->keymat,
-                                       ctx->ske->prop->cipher,
-                                       ctx->ske->prop->pkcs,
-                                       ctx->ske->prop->hash,
-                                       ctx->ske->prop->hmac,
-                                       ctx->ske->prop->group,
-                                       ctx->responder)) {
-    SILC_LOG_ERROR(("Error setting key material in use"));
-    silc_protocol_free(protocol);
-    sock->protocol = NULL;
-    silc_ske_free_key_material(ctx->keymat);
-    if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx->dest_id);
-    silc_server_config_unref(&ctx->cconfig);
-    silc_server_config_unref(&ctx->sconfig);
-    silc_server_config_unref(&ctx->rconfig);
-    silc_free(ctx);
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
-    server->stat.auth_failures++;
-    return;
+  /* Parse the incoming packet type */
+  silc_server_packet_parse_type(server, sock, packet);
+
+  /* Broadcast packet if it is marked as broadcast packet and it is
+     originated from router and we are router. */
+  if (server->server_type == SILC_ROUTER &&
+      sock->type == SILC_CONN_ROUTER &&
+      packet->flags & SILC_PACKET_FLAG_BROADCAST) {
+    /* Broadcast to our primary route */
+    silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet);
+
+    /* If we have backup routers then we need to feed all broadcast
+       data to those servers. */
+    silc_server_backup_broadcast(server, sock, packet);
   }
-  silc_ske_free_key_material(ctx->keymat);
-
-  /* Allocate internal context for the authentication protocol. This
-     is sent as context for the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->server = (void *)server;
-  proto_ctx->sock = sock;
-  proto_ctx->ske = ctx->ske;   /* Save SKE object from previous protocol */
-  proto_ctx->responder = TRUE;
-  proto_ctx->dest_id_type = ctx->dest_id_type;
-  proto_ctx->dest_id = ctx->dest_id;
-  proto_ctx->cconfig = ctx->cconfig;
-  proto_ctx->sconfig = ctx->sconfig;
-  proto_ctx->rconfig = ctx->rconfig;
-
-  /* Free old protocol as it is finished now */
-  silc_protocol_free(protocol);
-  if (ctx->packet)
-    silc_packet_context_free(ctx->packet);
-  silc_free(ctx);
-  sock->protocol = NULL;
-
-  /* Allocate the authentication protocol. This is allocated here
-     but we won't start it yet. We will be receiving party of this
-     protocol thus we will wait that connecting party will make
-     their first move. */
-  SILC_LOG_DEBUG(("Starting connection authentication protocol"));
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
-                     &sock->protocol, proto_ctx,
-                     silc_server_accept_new_connection_final);
-
-  /* Register timeout task. If the protocol is not executed inside
-     this timelimit the connection will be terminated. */
-  proto_ctx->timeout_task =
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_timeout_remote,
-                          (void *)server,
-                          server->config->conn_auth_timeout, 0,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW);
+
+ out:
+  silc_packet_context_free(packet);
+  silc_free(parse_ctx);
 }
+#endif /* 0 */
 
-/* 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)
+/******************************* Connecting *********************************/
+
+/* Free connection context */
+
+static void silc_server_connection_free(SilcServerConnection sconn)
 {
-  SilcServer server = context;
-  server->wait_backup = FALSE;
+  silc_dlist_del(sconn->server->conns, sconn);
+  silc_server_config_unref(&sconn->conn);
+  silc_free(sconn->remote_host);
+  silc_free(sconn->backup_replace_ip);
+  silc_free(sconn);
 }
 
-/* Final part of accepting new connection. The connection has now
-   been authenticated and keys has been exchanged. We also know whether
-   this is client or server connection. */
+/* Creates connection to a remote router. */
 
-SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
+void silc_server_create_connection(SilcServer server,
+                                  SilcBool reconnect,
+                                  const char *remote_host, SilcUInt32 port,
+                                  SilcServerConnectCallback callback,
+                                  void *context)
 {
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerConnAuthInternalContext *ctx =
-    (SilcServerConnAuthInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-  SilcSocketConnection sock = ctx->sock;
-  SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
-  void *id_entry;
-  SilcServerConfigConnParams *param = &server->config->param;
+  SilcServerConnection sconn;
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-    /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error during authentication protocol"));
-    silc_protocol_free(protocol);
-    sock->protocol = NULL;
-    if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx->dest_id);
-    silc_server_config_unref(&ctx->cconfig);
-    silc_server_config_unref(&ctx->sconfig);
-    silc_server_config_unref(&ctx->rconfig);
-    silc_free(ctx);
-
-    if (!SILC_IS_DISCONNECTING(sock)) {
-      SILC_LOG_INFO(("Authentication failed for %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")));
-      silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
-                                   NULL);
-    }
-    server->stat.auth_failures++;
+  /* Allocate connection object for hold connection specific stuff. */
+  sconn = silc_calloc(1, sizeof(*sconn));
+  if (!sconn)
     return;
-  }
-
-  entry->data.last_receive = time(NULL);
+  sconn->remote_host = strdup(remote_host);
+  sconn->remote_port = port;
+  sconn->no_reconnect = reconnect == FALSE;
+  sconn->callback = callback;
+  sconn->callback_context = context;
 
-  switch (ctx->conn_type) {
-  case SILC_SOCKET_TYPE_CLIENT:
-    {
-      SilcClientEntry client;
-      SilcServerConfigClient *conn = ctx->cconfig.ref_ptr;
+  silc_schedule_task_add_timeout(server->schedule, silc_server_connect_router,
+                                sconn, 0, 0);
+}
 
-      /* Verify whether this connection is after all allowed to connect */
-      if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
-                                         &server->config->param,
-                                         conn->param, ctx->ske)) {
-       server->stat.auth_failures++;
-       goto out;
-      }
+/* Connection authentication completion callback */
 
-      /* If we are primary router and we have backup router configured
-        but it has not connected to use yet, do not accept any other
-        connection. */
-      if (server->wait_backup && server->server_type == SILC_ROUTER &&
-         !server->backup_router) {
-       SilcServerConfigRouter *router;
-       router = silc_server_config_get_backup_router(server);
-       if (router && strcmp(server->config->server_info->primary->server_ip,
-                            sock->ip) &&
-           silc_server_find_socket_by_host(server,
-                                           SILC_SOCKET_TYPE_SERVER,
-                                           router->backup_replace_ip, 0)) {
-         SILC_LOG_INFO(("Will not accept connections because we do "
-                        "not have backup router connection established"));
-         sock->protocol = NULL;
-         silc_server_disconnect_remote(server, sock,
-                                       SILC_STATUS_ERR_PERM_DENIED,
-                                       "We do not have connection to backup "
-                                       "router established, try later");
-         silc_free(sock->user_data);
-         server->stat.auth_failures++;
+static void
+silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
+                         void *context)
+{
+  SilcServerConnection sconn = context;
+  SilcUnknownEntry entry = silc_packet_get_context(sconn->sock);
+  SilcServer server = entry->server;
+  SilcServerConfigServer *conn;
+  SilcServerConfigConnParams *param;
+  SilcIDListData idata;
+  SilcServerEntry id_entry;
+  unsigned char id[32];
+  SilcUInt32 id_len;
+  SilcID remote_id;
 
-         /* From here on, wait 20 seconds for the backup router to appear. */
-         silc_schedule_task_add(server->schedule, 0,
-                                silc_server_backup_router_wait,
-                                (void *)server, 20, 0,
-                                SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-         goto out;
-       }
-      }
+  SILC_LOG_DEBUG(("Connection authentication completed"));
 
-      SILC_LOG_DEBUG(("Remote host is client"));
-      SILC_LOG_INFO(("Connection %s (%s) is client", sock->hostname,
-                    sock->ip));
+  if (success == FALSE) {
+    /* Authentication failed */
+    /* XXX retry connecting */
 
-      /* Add the client to the client ID cache. The nickname and Client ID
-        and other information is created after we have received NEW_CLIENT
-        packet from client. */
-      client = silc_idlist_add_client(server->local_list,
-                                     NULL, NULL, NULL, NULL, NULL, sock, 0);
-      if (!client) {
-       SILC_LOG_ERROR(("Could not add new client to cache"));
-       silc_free(sock->user_data);
-       sock->protocol = NULL;
-       silc_server_disconnect_remote(server, sock,
-                                     SILC_STATUS_ERR_AUTH_FAILED, NULL);
-       server->stat.auth_failures++;
-       goto out;
-      }
-      entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_AUTH_FAILED, NULL);
+    return;
+  }
 
-      /* Statistics */
-      server->stat.my_clients++;
-      server->stat.clients++;
-      server->stat.cell_clients++;
+  SILC_LOG_INFO(("Connected to %s %s",
+                SILC_CONNTYPE_STRING(entry->data.conn_type),
+                sconn->remote_host));
+
+  /* Create the actual entry for remote entity */
+  switch (entry->data.conn_type) {
+  case SILC_CONN_SERVER:
+    SILC_LOG_DEBUG(("Remote is SILC server"));
+
+    /* Add new server.  The server must register itself to us before it
+       becomes registered to SILC network. */
+    id_entry = silc_idlist_add_server(server->local_list,
+                                     strdup(sconn->remote_host),
+                                     SILC_SERVER, NULL, NULL, sconn->sock);
+    if (!id_entry) {
+      silc_server_disconnect_remote(server, sconn->sock,
+                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+      silc_server_connection_free(sconn);
+      silc_free(entry);
+      return;
+    }
 
-      /* Get connection parameters */
-      if (conn->param) {
-       param = conn->param;
+    silc_idlist_add_data(id_entry, (SilcIDListData)entry);
+    break;
 
-       if (!param->keepalive_secs)
-         param->keepalive_secs = server->config->param.keepalive_secs;
+  case SILC_CONN_ROUTER:
+    SILC_LOG_DEBUG(("Remote is SILC router"));
 
-       if (!param->qos && server->config->param.qos) {
-         param->qos = server->config->param.qos;
-         param->qos_rate_limit = server->config->param.qos_rate_limit;
-         param->qos_bytes_limit = server->config->param.qos_bytes_limit;
-         param->qos_limit_sec = server->config->param.qos_limit_sec;
-         param->qos_limit_usec = server->config->param.qos_limit_usec;
-       }
+    /* Register to network */
+    silc_id_id2str(server->id, SILC_ID_SERVER, id, sizeof(id), &id_len);
+    if (!silc_packet_send_va(sconn->sock, SILC_PACKET_NEW_SERVER, 0,
+                            SILC_STR_UI_SHORT(id_len),
+                            SILC_STR_DATA(id, id_len),
+                            SILC_STR_UI_SHORT(strlen(server->server_name)),
+                            SILC_STR_DATA(server->server_name,
+                                          strlen(server->server_name)),
+                            SILC_STR_END)) {
+      silc_server_disconnect_remote(server, sconn->sock,
+                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+      silc_server_connection_free(sconn);
+      silc_free(entry);
+      return;
+    }
 
-       /* Check if to be anonymous connection */
-       if (param->anonymous)
-         client->mode |= SILC_UMODE_ANONYMOUS;
-      }
+    /* Get remote ID */
+    silc_packet_get_ids(sconn->sock, NULL, NULL, NULL, &remote_id);
 
-      /* Add public key to hash list (for whois using attributes) */
-      if (!silc_hash_table_find_by_context(server->pk_hash,
-                                          entry->data.public_key,
-                                          client, NULL))
-       silc_hash_table_add(server->pk_hash,
-                           entry->data.public_key, client);
+    /* Check that we do not have this ID already */
+    id_entry = silc_idlist_find_server_by_id(server->local_list,
+                                            &remote_id.u.server_id,
+                                            TRUE, NULL);
+    if (id_entry) {
+      silc_idcache_del_by_context(server->local_list->servers, id_entry, NULL);
+    } else {
+      id_entry = silc_idlist_find_server_by_id(server->global_list,
+                                              &remote_id.u.server_id,
+                                              TRUE, NULL);
+      if (id_entry)
+       silc_idcache_del_by_context(server->global_list->servers, id_entry,
+                                   NULL);
+    }
 
-      id_entry = (void *)client;
-      break;
+    SILC_LOG_DEBUG(("New server id(%s)",
+                   silc_id_render(&remote_id.u.server_id, SILC_ID_SERVER)));
+
+    /* 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(sconn->remote_host),
+                                     SILC_ROUTER, &remote_id.u.server_id,
+                                     NULL, sconn->sock);
+    if (!id_entry) {
+      silc_server_disconnect_remote(server, sconn->sock,
+                                   SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+      silc_server_connection_free(sconn);
+      silc_free(entry);
+      return;
     }
-  case SILC_SOCKET_TYPE_SERVER:
-  case SILC_SOCKET_TYPE_ROUTER:
-    {
-      SilcServerEntry new_server;
-      bool initiator = FALSE;
-      bool backup_local = FALSE;
-      bool backup_router = FALSE;
-      char *backup_replace_ip = NULL;
-      SilcUInt16 backup_replace_port = 0;
-      SilcServerConfigServer *sconn = ctx->sconfig.ref_ptr;
-      SilcServerConfigRouter *rconn = ctx->rconfig.ref_ptr;
 
-      /* If we are backup router and this is incoming server connection
-        and we do not have connection to primary router, do not allow
-        the connection. */
-      if (server->server_type == SILC_BACKUP_ROUTER &&
-         ctx->conn_type == SILC_SOCKET_TYPE_SERVER &&
-         !SILC_PRIMARY_ROUTE(server)) {
-       SILC_LOG_INFO(("Will not accept server connection because we do "
-                      "not have primary router connection established"));
-       sock->protocol = NULL;
-       silc_server_disconnect_remote(server, sock,
-                                     SILC_STATUS_ERR_PERM_DENIED,
-                                     "We do not have connection to primary "
-                                     "router established, try later");
-       silc_free(sock->user_data);
-       server->stat.auth_failures++;
-       goto out;
-      }
+    /* Registered */
+    silc_idlist_add_data(id_entry, (SilcIDListData)entry);
+    idata = (SilcIDListData)entry;
+    idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
+                     SILC_IDLIST_STATUS_LOCAL);
+
+    if (!sconn->backup) {
+      /* Mark this router our primary router if we're still standalone */
+      if (server->standalone) {
+       SILC_LOG_DEBUG(("This connection is our primary router"));
+       server->id_entry->router = id_entry;
+       server->router = id_entry;
+       server->router->server_type = SILC_ROUTER;
+       server->standalone = FALSE;
+       server->backup_primary = FALSE;
 
-      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
-       /* Verify whether this connection is after all allowed to connect */
-       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
-                                           &server->config->param,
-                                           rconn ? rconn->param : NULL,
-                                           ctx->ske)) {
-         silc_free(sock->user_data);
-         server->stat.auth_failures++;
-         goto out;
+       /* Announce data if we are not backup router (unless not as primary
+          currently).  Backup router announces later at the end of
+          resuming protocol. */
+       if (server->backup_router && server->server_type == SILC_ROUTER) {
+         SILC_LOG_DEBUG(("Announce data after resume protocol"));
+       } else {
+         /* 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,
+                                        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));
+         silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
        }
 
-       if (rconn) {
-         if (rconn->param) {
-           param = rconn->param;
+#if 0
+       /* 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,
+                                sconn->remote_port, TRUE);
+#endif /* 0 */
+      }
+    } else {
+      /* Add this server to be our backup router */
+      id_entry->server_type = SILC_BACKUP_ROUTER;
+      silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
+                            sconn->backup_replace_port, FALSE);
+    }
 
-           if (!param->keepalive_secs)
-             param->keepalive_secs = server->config->param.keepalive_secs;
+    break;
 
-           if (!param->qos && server->config->param.qos) {
-             param->qos = server->config->param.qos;
-             param->qos_rate_limit = server->config->param.qos_rate_limit;
-             param->qos_bytes_limit = server->config->param.qos_bytes_limit;
-             param->qos_limit_sec = server->config->param.qos_limit_sec;
-             param->qos_limit_usec = server->config->param.qos_limit_usec;
-           }
-         }
+  default:
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_AUTH_FAILED, NULL);
+    silc_server_connection_free(sconn);
+    silc_free(entry);
+    return;
+  }
 
-         initiator = rconn->initiator;
-         backup_local = rconn->backup_local;
-         backup_router = rconn->backup_router;
-         backup_replace_ip = rconn->backup_replace_ip;
-         backup_replace_port = rconn->backup_replace_port;
-       }
-      }
+  conn = sconn->conn.ref_ptr;
+  param = &server->config->param;
+  if (conn && conn->param)
+    param = conn->param;
 
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
-       /* Verify whether this connection is after all allowed to connect */
-       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
-                                           &server->config->param,
-                                           sconn ? sconn->param : NULL,
-                                           ctx->ske)) {
-         silc_free(sock->user_data);
-         server->stat.auth_failures++;
-         goto out;
-       }
-       if (sconn) {
-         if (sconn->param) {
-           param = sconn->param;
+  /* Register rekey timeout */
+  sconn->rekey_timeout = param->key_exchange_rekey;
+  silc_schedule_task_add_timeout(server->schedule, silc_server_do_rekey,
+                                sconn->sock, sconn->rekey_timeout, 0);
 
-           if (!param->keepalive_secs)
-             param->keepalive_secs = server->config->param.keepalive_secs;
+#if 0
+  /* Perform keepalive. */
+  silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
+                           silc_server_perform_heartbeat,
+                           server->schedule);
 
-           if (!param->qos && server->config->param.qos) {
-             param->qos = server->config->param.qos;
-             param->qos_rate_limit = server->config->param.qos_rate_limit;
-             param->qos_bytes_limit = server->config->param.qos_bytes_limit;
-             param->qos_limit_sec = server->config->param.qos_limit_sec;
-             param->qos_limit_usec = server->config->param.qos_limit_usec;
-           }
-         }
+ out:
+  /* Call the completion callback to indicate that we've connected to
+     the router */
+  if (sconn && sconn->callback)
+    (*sconn->callback)(server, id_entry, sconn->callback_context);
 
-         backup_router = sconn->backup_router;
-       }
-      }
+  /* Free the temporary connection data context */
+  if (sconn) {
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
+  }
+  if (sconn == server->router_conn)
+    server->router_conn = NULL;
+#endif /* 0 */
 
-      /* If we are primary router and we have backup router configured
-        but it has not connected to use yet, do not accept any other
-        connection. */
-      if (server->wait_backup && server->server_type == SILC_ROUTER &&
-         !server->backup_router && !backup_router) {
-       SilcServerConfigRouter *router;
-       router = silc_server_config_get_backup_router(server);
-       if (router && strcmp(server->config->server_info->primary->server_ip,
-                            sock->ip) &&
-           silc_server_find_socket_by_host(server,
-                                           SILC_SOCKET_TYPE_SERVER,
-                                           router->backup_replace_ip, 0)) {
-         SILC_LOG_INFO(("Will not accept connections because we do "
-                        "not have backup router connection established"));
-         sock->protocol = NULL;
-         silc_server_disconnect_remote(server, sock,
-                                       SILC_STATUS_ERR_PERM_DENIED,
-                                       "We do not have connection to backup "
-                                       "router established, try later");
-         silc_free(sock->user_data);
-         server->stat.auth_failures++;
+  silc_free(entry);
+}
 
-         /* From here on, wait 20 seconds for the backup router to appear. */
-         silc_schedule_task_add(server->schedule, 0,
-                                silc_server_backup_router_wait,
-                                (void *)server, 20, 0,
-                                SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-         goto out;
-       }
-      }
+/* SKE completion callback */
 
-      SILC_LOG_DEBUG(("Remote host is %s",
-                     ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                     "server" : (backup_router ?
-                                 "backup router" : "router")));
-      SILC_LOG_INFO(("Connection %s (%s) is %s", sock->hostname,
-                    sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                    "server" : (backup_router ?
-                                "backup router" : "router")));
+static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
+                                    SilcSKESecurityProperties prop,
+                                    SilcSKEKeyMaterial keymat,
+                                    SilcSKERekeyMaterial rekey,
+                                    void *context)
+{
+  SilcServerConnection sconn = context;
+  SilcUnknownEntry entry = silc_packet_get_context(sconn->sock);
+  SilcServer server = entry->server;
+  SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+  SilcAuthMethod auth_meth = SILC_AUTH_NONE;
+  void *auth_data = NULL;
+  SilcUInt32 auth_data_len = 0;
+  SilcConnAuth connauth;
+  SilcCipher send_key, receive_key;
+  SilcHmac hmac_send, hmac_receive;
+  SilcHash hash;
+
+  if (status != SILC_SKE_STATUS_OK) {
+    /* SKE failed */
+    SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
+                   silc_ske_map_status(status), entry->hostname, entry->ip));
+
+    /* XXX retry connecting */
+    silc_ske_free(ske);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+    silc_server_connection_free(sconn);
+    return;
+  }
 
-      /* Add the server into server cache. The server name and Server ID
-        is updated after we have received NEW_SERVER packet from the
-        server. We mark ourselves as router for this server if we really
-        are router. */
-      new_server =
-       silc_idlist_add_server((ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               server->local_list : (backup_router ?
-                                                     server->local_list :
-                                                     server->global_list)),
-                              NULL,
-                              (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               SILC_SERVER : SILC_ROUTER),
-                              NULL,
-                              (ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
-                               server->id_entry : (backup_router ?
-                                                   server->id_entry : NULL)),
-                              sock);
-      if (!new_server) {
-       SILC_LOG_ERROR(("Could not add new server to cache"));
-       silc_free(sock->user_data);
-       sock->protocol = NULL;
-       silc_server_disconnect_remote(server, sock,
-                                     SILC_STATUS_ERR_AUTH_FAILED, NULL);
-       server->stat.auth_failures++;
-       goto out;
-      }
-      entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
+  SILC_LOG_DEBUG(("Setting keys into use"));
 
-      id_entry = (void *)new_server;
+  /* Set the keys into use.  The data will be encrypted after this. */
+  if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
+                        &hmac_send, &hmac_receive, &hash)) {
 
-      /* 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) {
-       /* 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;
+    /* XXX retry connecting */
 
-       SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
-                              ("Backup router %s is now online",
-                               sock->hostname));
+    /* Error setting keys */
+    silc_ske_free(ske);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+    silc_server_connection_free(sconn);
+    return;
+  }
+  silc_packet_set_keys(sconn->sock, send_key, receive_key, hmac_send,
+                      hmac_receive, FALSE);
 
-       /* Remove the backup waiting with timeout */
-       silc_schedule_task_add(server->schedule, 0,
-                              silc_server_backup_router_wait,
-                              (void *)server, 10, 0,
-                              SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-      }
+  SILC_LOG_DEBUG(("Starting connection authentication"));
 
-      /* Statistics */
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
-       server->stat.my_servers++;
-       server->stat.servers++;
+  connauth = silc_connauth_alloc(server->schedule, ske,
+                                server->config->conn_auth_timeout);
+  if (!connauth) {
+    /* XXX retry connecting */
+
+    /** Error allocating auth protocol */
+    silc_ske_free(ske);
+    silc_server_disconnect_remote(server, sconn->sock,
+                                 SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+    silc_server_connection_free(sconn);
+    return;
+  }
+
+  /* Get authentication method */
+  if (conn) {
+    if (conn->passphrase) {
+      if (conn->publickeys && !server->config->prefer_passphrase_auth) {
+       auth_meth = SILC_AUTH_PUBLIC_KEY;
+       auth_data = server->private_key;
       } else {
-       server->stat.my_routers++;
-       server->stat.routers++;
+       auth_meth = SILC_AUTH_PASSWORD;
+       auth_data = conn->passphrase;
+       auth_data_len = conn->passphrase_len;
       }
+    } else {
+      auth_meth = SILC_AUTH_PUBLIC_KEY;
+      auth_data = server->private_key;
+    }
+  }
 
-      /* Check whether this connection is to be our primary router connection
-        if we do not already have the primary route. */
-      if (!backup_router &&
-         server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
-       if (silc_server_config_is_primary_route(server) && !initiator)
-         break;
+  /* Start connection authentication */
+  silc_connauth_initiator(connauth, server->server_type == SILC_ROUTER ?
+                         SILC_CONN_ROUTER : SILC_CONN_SERVER, auth_meth,
+                         auth_data, auth_data_len,
+                         silc_server_ke_auth_compl, sconn);
+}
 
-       SILC_LOG_DEBUG(("We are not standalone server anymore"));
-       server->standalone = FALSE;
-       if (!server->id_entry->router) {
-         server->id_entry->router = id_entry;
-         server->router = id_entry;
-       }
-      }
+/* Function that is called when the network connection to a router has
+   been established.  This will continue with the key exchange protocol
+   with the remote router. */
 
-      break;
-    }
-  default:
-    goto out;
-    break;
+void silc_server_start_key_exchange(SilcServerConnection sconn)
+{
+  SilcServer server = sconn->server;
+  SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+  SilcUnknownEntry entry;
+  SilcSKEParamsStruct params;
+  SilcSKE ske;
+
+  /* Cancel any possible retry timeouts */
+  silc_schedule_task_del_by_context(server->schedule, sconn);
+
+  /* Create packet stream */
+  sconn->sock = silc_packet_stream_create(server->packet_engine,
+                                         server->schedule, sconn->stream);
+  if (!sconn->sock) {
+    SILC_LOG_ERROR(("Cannot connect: cannot create packet stream"));
+    silc_stream_destroy(sconn->stream);
+    silc_server_connection_free(sconn);
+    return;
   }
+  server->stat.conn_num++;
 
-  sock->type = ctx->conn_type;
+  /* Set source ID to packet stream */
+  if (!silc_packet_set_ids(sconn->sock, SILC_ID_SERVER, &server->id,
+                          0, NULL)) {
+    silc_packet_stream_destroy(sconn->sock);
+    silc_server_connection_free(sconn);
+    return;
+  }
 
-  /* Add the common data structure to the ID entry. */
-  silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
+  /* Create entry for remote entity */
+  entry = silc_calloc(1, sizeof(*entry));
+  if (!entry) {
+    silc_packet_stream_destroy(sconn->sock);
+    silc_server_connection_free(sconn);
+    return;
+  }
+  entry->server = server;
+  silc_packet_set_context(sconn->sock, entry);
 
-  /* Add to sockets internal pointer for fast referencing */
-  silc_free(sock->user_data);
-  sock->user_data = id_entry;
+  /* Set Key Exchange flags from configuration, but fall back to global
+     settings too. */
+  memset(&params, 0, sizeof(params));
+  SILC_GET_SKE_FLAGS(conn, params.flags);
+  if (server->config->param.key_exchange_pfs)
+    params.flags |= SILC_SKE_SP_FLAG_PFS;
 
-  /* Connection has been fully established now. Everything is ok. */
-  SILC_LOG_DEBUG(("New connection authenticated"));
+  /* Start SILC Key Exchange protocol */
+  SILC_LOG_DEBUG(("Starting key exchange protocol"));
+  ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
+                      server->public_key, server->private_key, sconn->sock);
+  if (!ske) {
+    silc_free(entry);
+    silc_packet_stream_destroy(sconn->sock);
+    silc_server_connection_free(sconn);
+    return;
+  }
+  silc_ske_set_callbacks(ske, silc_server_verify_key,
+                        silc_server_ke_completed, sconn->sock);
+
+  /* Start key exchange protocol */
+  params.version = silc_version_string;
+  params.timeout_secs = server->config->key_exchange_timeout;
+  silc_ske_initiator(ske, sconn->sock, &params, NULL);
+}
+
+/* Timeout callback that will be called to retry connecting to remote
+   router. This is used by both normal and router server. This will wait
+   before retrying the connecting. The timeout is generated by exponential
+   backoff algorithm. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
+{
+  SilcServerConnection sconn = context;
+  SilcServer server = sconn->server;
+  SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+  SilcServerConfigConnParams *param =
+               (conn->param ? conn->param : &server->config->param);
+
+  SILC_LOG_INFO(("Retrying connecting to %s:%d", sconn->remote_host,
+                sconn->remote_port));
+
+  /* Calculate next timeout */
+  if (sconn->retry_count >= 1) {
+    sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
+    if (sconn->retry_timeout > param->reconnect_interval_max)
+      sconn->retry_timeout = param->reconnect_interval_max;
+  } else {
+    sconn->retry_timeout = param->reconnect_interval;
+  }
+  sconn->retry_count++;
+  sconn->retry_timeout = sconn->retry_timeout +
+    (silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER);
+
+  /* If we've reached max retry count, give up. */
+  if ((sconn->retry_count > param->reconnect_count) &&
+      !param->reconnect_keep_trying) {
+    SILC_LOG_ERROR(("Could not connect, giving up"));
+    silc_server_connection_free(sconn);
+    return;
+  }
 
-  /* Perform keepalive. */
-  if (param->keepalive_secs)
-    silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
-                             silc_server_perform_heartbeat,
-                             server->schedule);
+  SILC_LOG_DEBUG(("Retrying connecting %d seconds", sconn->retry_timeout));
 
-  /* Perform Quality of Service */
-  if (param->qos)
-    silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit,
-                       param->qos_limit_sec, param->qos_limit_usec,
-                       server->schedule);
+  /* We will lookup a fresh pointer later */
+  silc_server_config_unref(&sconn->conn);
 
- out:
-  if (sock->protocol == protocol)
-    silc_protocol_free(protocol);
-  if (ctx->packet)
-    silc_packet_context_free(ctx->packet);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
-  silc_free(ctx->dest_id);
-  silc_server_config_unref(&ctx->cconfig);
-  silc_server_config_unref(&ctx->sconfig);
-  silc_server_config_unref(&ctx->rconfig);
-  silc_free(ctx);
-  sock->protocol = NULL;
+  /* Wait before retrying */
+  silc_schedule_task_del_by_context(server->schedule, sconn);
+  silc_schedule_task_add_timeout(server->schedule, silc_server_connect_router,
+                                sconn, sconn->retry_timeout, 0);
 }
 
-/* This function is used to read packets from network and send packets to
-   network. This is usually a generic task. */
+/* Callback for async connection to remote router */
 
-SILC_TASK_CALLBACK(silc_server_packet_process)
+static void silc_server_connection_established(SilcNetStatus status,
+                                              SilcStream stream,
+                                              void *context)
 {
-  SilcServer server = (SilcServer)context;
-  SilcSocketConnection sock = server->sockets[fd];
-  SilcIDListData idata;
-  SilcCipher cipher = NULL;
-  SilcHmac hmac = NULL;
-  SilcUInt32 sequence = 0;
-  bool local_is_router;
-  int ret;
-
-  if (!sock) {
-    SILC_LOG_DEBUG(("Unknown socket connection"));
-    return;
-  }
-
-  /* Packet sending */
+  SilcServerConnection sconn = context;
+  SilcServer server = sconn->server;
 
-  if (type == SILC_TASK_WRITE) {
-    /* Do not send data to disconnected connection */
-    if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
-      SILC_LOG_DEBUG(("Disconnected socket connection, cannot send"));
-      SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
-      SILC_UNSET_OUTBUF_PENDING(sock);
-      silc_buffer_clear(sock->outbuf);
-      return;
-    }
+  silc_schedule_task_del_by_context(server->schedule, sconn);
+  sconn->op = NULL;
 
-    server->stat.packets_sent++;
-
-    /* Send the packet */
-    ret = silc_packet_send(sock, TRUE);
+  switch (status) {
+  case SILC_NET_OK:
+    SILC_LOG_DEBUG(("Connection to %s:%d established",
+                   sconn->remote_host, sconn->remote_port));
 
-    /* If returned -2 could not write to connection now, will do
-       it later. */
-    if (ret == -2)
-      return;
+    /* Continue with key exchange protocol */
+    sconn->stream = stream;
+    silc_server_start_key_exchange(sconn);
+    break;
 
-    /* The packet has been sent and now it is time to set the connection
-       back to only for input. When there is again some outgoing data
-       available for this connection it will be set for output as well.
-       This call clears the output setting and sets it only for input. */
-    SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
-    SILC_UNSET_OUTBUF_PENDING(sock);
-    silc_buffer_clear(sock->outbuf);
-
-    if (ret == -1) {
-      SILC_LOG_ERROR(("Error sending packet to 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")));
-
-      if (sock->user_data) {
-       /* If backup then mark that resuming will not be allowed */
-       if (server->server_type == SILC_ROUTER && !server->backup_router &&
-           sock->type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerEntry server_entry = sock->user_data;
-         if (server_entry->server_type == SILC_BACKUP_ROUTER)
-           server->backup_closed = TRUE;
-       }
+  case SILC_NET_UNKNOWN_IP:
+  case SILC_NET_UNKNOWN_HOST:
+    SILC_LOG_ERROR(("Could not connect to %s:%d: %s",
+                   sconn->remote_host, sconn->remote_port,
+                   silc_net_get_error_string(status)));
+    silc_server_connection_free(sconn);
+    break;
 
-       silc_server_free_sock_user_data(server, sock, NULL);
-      }
-      SILC_SET_DISCONNECTING(sock);
-      silc_server_close_connection(server, sock);
+  default:
+    SILC_LOG_ERROR(("Could not connect to %s:%d: %s",
+                   sconn->remote_host, sconn->remote_port,
+                   silc_net_get_error_string(status)));
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(sconn->server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+    } else {
+      silc_server_connection_free(sconn);
     }
-    return;
+    break;
   }
+}
 
-  /* Packet receiving */
-
-  /* Read some data from connection */
-  ret = silc_packet_receive(sock);
-  if (ret < 0) {
+/* Generic routine to use connect to a router. */
 
-    if (ret == -1) {
-      SILC_LOG_ERROR(("Error receiving packet from 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"), strerror(errno)));
+SILC_TASK_CALLBACK(silc_server_connect_router)
+{
+  SilcServerConnection sconn = context;
+  SilcServer server = sconn->server;
+  SilcServerConfigRouter *rconn;
 
-      if (sock->user_data) {
-       /* If backup then mark that resuming will not be allowed */
-       if (server->server_type == SILC_ROUTER && !server->backup_router &&
-           sock->type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerEntry server_entry = sock->user_data;
-         if (server_entry->server_type == SILC_BACKUP_ROUTER)
-           server->backup_closed = TRUE;
-       }
+  silc_schedule_task_del_by_context(server->schedule, sconn);
 
-       silc_server_free_sock_user_data(server, sock, NULL);
-      }
-      SILC_SET_DISCONNECTING(sock);
-      silc_server_close_connection(server, sock);
-    }
+  /* Don't connect if we are shutting down. */
+  if (server->server_shutdown) {
+    silc_server_connection_free(sconn);
     return;
   }
 
-  /* EOF */
-  if (ret == 0) {
-    SILC_LOG_DEBUG(("Read EOF"));
+  SILC_LOG_INFO(("Connecting to the %s %s on port %d",
+                (sconn->backup ? "backup router" : "router"),
+                sconn->remote_host, sconn->remote_port));
 
-    /* If connection is disconnecting already we will finally
-       close the connection */
-    if (SILC_IS_DISCONNECTING(sock)) {
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      silc_server_close_connection(server, sock);
+  if (!server->no_conf) {
+    /* Find connection configuration */
+    rconn = silc_server_config_find_router_conn(server, sconn->remote_host,
+                                               sconn->remote_port);
+    if (!rconn) {
+      SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
+                    (sconn->backup ? "backup router" : "router"),
+                    sconn->remote_host, sconn->remote_port));
+      silc_server_connection_free(sconn);
       return;
     }
-
-    SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
-
-    if (sock->user_data) {
-      char tmp[128];
-
-      /* If backup disconnected then mark that resuming will not be allowed */
-      if (server->server_type == SILC_ROUTER && !server->backup_router &&
-         sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
-       SilcServerEntry server_entry = sock->user_data;
-       if (server_entry->server_type == SILC_BACKUP_ROUTER)
-         server->backup_closed = TRUE;
-      }
-
-      if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1))
-       silc_server_free_sock_user_data(server, sock, tmp);
-      else
-       silc_server_free_sock_user_data(server, sock, NULL);
-    } else if (server->router_conn && server->router_conn->sock == sock &&
-              !server->router && server->standalone) {
-      silc_server_create_connections(server);
-    }
-
-    SILC_SET_DISCONNECTING(sock);
-    silc_server_close_connection(server, sock);
-    return;
+    silc_server_config_ref(&sconn->conn, server->config, (void *)rconn);
   }
 
-  /* If connection is disconnecting or disconnected we will ignore
-     what we read. */
-  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
-    SILC_LOG_DEBUG(("Ignoring read data from disconnected connection"));
+  /* Connect to remote host */
+  sconn->op =
+    silc_net_tcp_connect((!server->config->server_info->primary ? NULL :
+                         server->config->server_info->primary->server_ip),
+                        sconn->remote_host, sconn->remote_port,
+                        server->schedule, silc_server_connection_established,
+                        sconn);
+  if (!sconn->op) {
+    SILC_LOG_ERROR(("Could not connect to router %s:%d",
+                   sconn->remote_host, sconn->remote_port));
+    silc_server_connection_free(sconn);
     return;
   }
 
-  /* Get keys and stuff from ID entry */
-  idata = (SilcIDListData)sock->user_data;
-  if (idata) {
-    cipher = idata->receive_key;
-    hmac = idata->hmac_receive;
-    sequence = idata->psn_receive;
-  }
-
-  /* Then, process the packet. This will call the parser that will then
-     decrypt and parse the packet. */
-
-  local_is_router = (server->server_type == SILC_ROUTER);
-
-  /* If socket connection is our primary, we are backup and we are doing
-     backup resuming, we won't process the packet as being a router
-     (affects channel message decryption). */
-  if (server->backup_router && SILC_SERVER_IS_BACKUP(sock) &&
-      SILC_PRIMARY_ROUTE(server) == sock)
-    local_is_router = FALSE;
-
-  ret = silc_packet_receive_process(sock, local_is_router,
-                                   cipher, hmac, sequence,
-                                   silc_server_packet_parse, server);
-
-  /* If processing failed the connection is closed. */
-  if (!ret) {
-    /* On packet processing errors we may close our primary router
-       connection but won't become primary router if we are the backup
-       since this is local error condition. */
-    if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
-      server->backup_noswitch = TRUE;
-
-    if (sock->user_data) {
-      /* If we are router and backup errorred then mark that resuming
-        will not be allowed */
-      if (server->server_type == SILC_ROUTER && !server->backup_router &&
-         sock->type == SILC_SOCKET_TYPE_SERVER) {
-       SilcServerEntry server_entry = sock->user_data;
-       if (server_entry->server_type == SILC_BACKUP_ROUTER)
-         server->backup_closed = TRUE;
-      }
-
-      silc_server_free_sock_user_data(server, sock, NULL);
-    }
-    SILC_SET_DISCONNECTING(sock);
-    silc_server_close_connection(server, sock);
-  }
+  /* Add to connection list */
+  silc_dlist_add(server->conns, sconn);
 }
 
-/* Parses whole packet, received earlier. */
+/* This function connects to our primary router or if we are a router this
+   establishes all our primary routes. This is called at the start of the
+   server to do authentication and key exchange with our router - called
+   from schedule. */
 
-SILC_TASK_CALLBACK(silc_server_packet_parse_real)
+SILC_TASK_CALLBACK(silc_server_connect_to_router)
 {
-  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
-  SilcServer server = (SilcServer)parse_ctx->context;
-  SilcSocketConnection sock = parse_ctx->sock;
-  SilcPacketContext *packet = parse_ctx->packet;
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
-  int ret;
-
-  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
-    SILC_LOG_DEBUG(("Connection is disconnected"));
-    goto out;
-  }
+  SilcServer server = context;
+  SilcServerConnection sconn;
+  SilcServerConfigRouter *ptr;
 
-  server->stat.packets_received++;
+  /* Don't connect if we are shutting down. */
+  if (server->server_shutdown)
+    return;
 
-  /* Parse the packet */
-  if (parse_ctx->normal)
-    ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
-  else
-    ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
+  SILC_LOG_DEBUG(("We are %s",
+                 (server->server_type == SILC_SERVER ?
+                  "normal server" : server->server_type == SILC_ROUTER ?
+                  "router" : "backup router/normal server")));
 
-  /* If entry is disabled ignore what we got. */
-  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 &&
-      ret != SILC_PACKET_KEY_EXCHANGE_1 && ret != SILC_PACKET_KEY_EXCHANGE_2) {
-    SILC_LOG_DEBUG(("Connection is disabled (packet %s dropped)",
-                   silc_get_packet_name(ret)));
-    goto out;
+  /* XXX */
+  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), we are standalone"));
+    server->standalone = TRUE;
+    return;
   }
 
-  if (ret == SILC_PACKET_NONE) {
-    SILC_LOG_DEBUG(("Error parsing packet"));
-    goto out;
-  }
+  /* Create the connections to all our routes */
+  for (ptr = server->config->routers; ptr; ptr = ptr->next) {
 
-  /* Check that the the current client ID is same as in the client's packet. */
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    SilcClientEntry client = (SilcClientEntry)sock->user_data;
-    if (client && client->id && packet->src_id) {
-      void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
-                               packet->src_id_type);
-      if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
-       silc_free(id);
-       SILC_LOG_DEBUG(("Packet source is not same as sender"));
-       goto out;
-      }
-      silc_free(id);
-    }
-  }
+    SILC_LOG_DEBUG(("%s connection [%s] %s:%d",
+                   ptr->backup_router ? "Backup router" : "Router",
+                   ptr->initiator ? "Initiator" : "Responder",
+                   ptr->host, ptr->port));
 
-  if (server->server_type == SILC_ROUTER) {
-    /* Route the packet if it is not destined to us. Other ID types but
-       server are handled separately after processing them. */
-    if (packet->dst_id && !(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
-       packet->dst_id_type == SILC_ID_SERVER &&
-       sock->type != SILC_SOCKET_TYPE_CLIENT &&
-       memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
-      SilcSocketConnection conn;
+    if (server->server_type == SILC_ROUTER && ptr->backup_router &&
+       ptr->initiator == FALSE && !server->backup_router &&
+       !silc_server_config_get_backup_router(server))
+      server->wait_backup = TRUE;
 
-      /* Route the packet to fastest route for the destination ID */
-      void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                               packet->dst_id_type);
-      if (!id)
-       goto out;
+    if (!ptr->initiator)
+      continue;
 
-      conn = silc_server_route_get(server, id, packet->dst_id_type);
-      if (!conn) {
-       SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
-                         silc_id_render(id, SILC_ID_SERVER)));
-       goto out;
+    /* Check whether we are connecting or connected to this host already */
+    if (silc_server_num_sockets_by_remote(server,
+                                         silc_net_is_ip(ptr->host) ?
+                                         ptr->host : NULL,
+                                         silc_net_is_ip(ptr->host) ?
+                                         NULL : ptr->host, ptr->port)) {
+      SILC_LOG_DEBUG(("We are already connected to %s:%d",
+                     ptr->host, ptr->port));
+
+      /* If we don't have primary router and this connection is our
+        primary router we are in desync.  Reconnect to the primary. */
+      if (server->standalone && !server->router) {
+       /* XXX */
+       SilcPacketStream sock;
+       SilcServerConfigRouter *primary =
+         silc_server_config_get_primary_router(server);
+       if (primary != ptr)
+         continue;
+       sock = silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+                                              ptr->host, ptr->port);
+       if (!sock)
+         continue;
+       server->backup_noswitch = TRUE;
+#if 0
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
+       silc_server_disconnect_remote(server, sock, 0, NULL);
+#endif /* 0 */
+       server->backup_noswitch = FALSE;
+       SILC_LOG_DEBUG(("Reconnecting to primary router"));
+      } else {
+       continue;
       }
+    }
 
-      silc_server_packet_route(server, conn, packet);
-      silc_free(id);
-      goto out;
+    /* Allocate connection object for hold connection specific stuff. */
+    sconn = silc_calloc(1, sizeof(*sconn));
+    if (!sconn)
+      continue;
+    sconn->remote_host = strdup(ptr->host);
+    sconn->remote_port = ptr->port;
+    sconn->backup = ptr->backup_router;
+    if (sconn->backup) {
+      sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
+      sconn->backup_replace_port = ptr->backup_replace_port;
     }
+
+    /* XXX */
+    if (!server->router_conn && !sconn->backup)
+      server->router_conn = sconn;
+
+    /* Connect */
+    silc_server_connect_router(server->schedule, server, SILC_TASK_EXPIRE,
+                              0, sconn);
   }
+}
 
-  /* Parse the incoming packet type */
-  silc_server_packet_parse_type(server, sock, packet);
 
-  /* Broadcast packet if it is marked as broadcast packet and it is
-     originated from router and we are router. */
-  if (server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_ROUTER &&
-      packet->flags & SILC_PACKET_FLAG_BROADCAST) {
-    /* Broadcast to our primary route */
-    silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet);
+/************************ Accepting new connection **************************/
 
-    /* If we have backup routers then we need to feed all broadcast
-       data to those servers. */
-    silc_server_backup_broadcast(server, sock, packet);
-  }
+/* After this is called, server don't wait for backup router anymore.
+   This gets called automatically even after we have backup router
+   connection established. */
 
- out:
-  silc_packet_context_free(packet);
-  silc_free(parse_ctx);
+SILC_TASK_CALLBACK(silc_server_backup_router_wait)
+{
+  SilcServer server = context;
+  server->wait_backup = FALSE;
 }
 
-/* Parser callback called by silc_packet_receive_process. This merely
-   registers timeout that will handle the actual parsing when appropriate. */
+/* Authentication data callback */
 
-bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
-                             void *context)
+static SilcBool
+silc_server_accept_get_auth(SilcConnAuth connauth,
+                           SilcConnectionType conn_type,
+                           unsigned char **passphrase,
+                           SilcUInt32 *passphrase_len,
+                           SilcSKR *repository,
+                           void *context)
 {
-  SilcServer server = (SilcServer)context;
-  SilcSocketConnection sock = parser_context->sock;
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
-  bool ret;
+  SilcPacketStream sock = context;
+  SilcUnknownEntry entry = silc_packet_get_context(sock);
+  SilcServer server = entry->server;
 
-  if (idata)
-    idata->psn_receive = parser_context->packet->sequence + 1;
+  SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
 
-  /* If protocol for this connection is key exchange or rekey then we'll
-     process all packets synchronously, since there might be packets in
-     queue that we are not able to decrypt without first processing the
-     packets before them. */
-  if (sock->protocol && sock->protocol->protocol &&
-      (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
-       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
-    silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
-                                 parser_context);
-
-    if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
-      SILC_LOG_DEBUG(("Connection is disconnected"));
+  /* Remote end is client */
+  if (conn_type == SILC_CONN_CLIENT) {
+    SilcServerConfigClient *cconfig = entry->cconfig.ref_ptr;
+    if (!cconfig)
       return FALSE;
-    }
 
-    /* Reprocess data since we'll return FALSE here.  This is because
-       the idata->receive_key might have become valid in the last packet
-       and we want to call this processor with valid cipher. */
-    if (idata)
-      ret = silc_packet_receive_process(
-                                 sock, server->server_type == SILC_ROUTER,
-                                 idata->receive_key,
-                                 idata->hmac_receive, idata->psn_receive,
-                                 silc_server_packet_parse, server);
-    else
-      ret = silc_packet_receive_process(
-                                 sock, server->server_type == SILC_ROUTER,
-                                 NULL, NULL, 0,
-                                 silc_server_packet_parse, server);
-
-    if (!ret) {
-      /* On packet processing errors we may close our primary router
-         connection but won't become primary router if we are the backup
-         since this is local error condition. */
-      if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
-       server->backup_noswitch = TRUE;
+    *passphrase = cconfig->passphrase;
+    *passphrase_len = cconfig->passphrase_len;
+    if (cconfig->publickeys)
+      *repository = server->repository;
 
-      if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock, NULL);
-      SILC_SET_DISCONNECTING(sock);
-      silc_server_close_connection(server, sock);
-    }
+    entry->data.conn_type = conn_type;
+    return TRUE;
+  }
 
-    return FALSE;
+  /* Remote end is server */
+  if (conn_type == SILC_CONN_SERVER) {
+    SilcServerConfigServer *sconfig = entry->sconfig.ref_ptr;
+    if (!sconfig)
+      return FALSE;
+
+    *passphrase = sconfig->passphrase;
+    *passphrase_len = sconfig->passphrase_len;
+    if (sconfig->publickeys)
+      *repository = server->repository;
+
+    entry->data.conn_type = conn_type;
+    return TRUE;
   }
 
-  switch (sock->type) {
-  case SILC_SOCKET_TYPE_UNKNOWN:
-  case SILC_SOCKET_TYPE_CLIENT:
-    /* Parse the packet with timeout */
-    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 immediately */
-    silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
-                                 parser_context);
-    break;
+  /* Remote end is router */
+  if (conn_type == SILC_CONN_ROUTER) {
+    SilcServerConfigRouter *rconfig = entry->rconfig.ref_ptr;
+    if (!rconfig)
+      return FALSE;
+
+    *passphrase = rconfig->passphrase;
+    *passphrase_len = rconfig->passphrase_len;
+    if (rconfig->publickeys)
+      *repository = server->repository;
+
+    entry->data.conn_type = conn_type;
+    return TRUE;
   }
 
-  return TRUE;
+  return FALSE;
 }
 
-/* Parses the packet type and calls what ever routines the packet type
-   requires. This is done for all incoming packets. */
+/* Authentication completion callback. */
 
-void silc_server_packet_parse_type(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  SilcPacketContext *packet)
+static void
+silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
+                             void *context)
 {
-  SilcPacketType type = packet->type;
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
+  SilcPacketStream sock = context;
+  SilcUnknownEntry entry = silc_packet_get_context(sock);
+  SilcServer server = entry->server;
+  SilcServerConfigConnParams *param;
+  void *id_entry;
 
-  SILC_LOG_DEBUG(("Received %s packet [flags %d]",
-                 silc_get_packet_name(type), packet->flags));
+  if (success == FALSE) {
+    /* Authentication failed */
+    SILC_LOG_INFO(("Authentication failed for %s (%s) [%s]", entry->hostname,
+                  entry->ip, SILC_CONNTYPE_STRING(entry->data.conn_type)));
+    server->stat.auth_failures++;
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+    goto out;
+  }
 
-  /* Parse the packet type */
-  switch (type) {
-  case SILC_PACKET_DISCONNECT:
+  SILC_LOG_DEBUG(("Checking whether connection is allowed"));
+
+  switch (entry->data.conn_type) {
+  case SILC_CONN_CLIENT:
     {
-      SilcStatus status;
-      char *message = NULL;
+      SilcClientEntry client;
+      SilcServerConfigClient *conn = entry->cconfig.ref_ptr;
 
-      if (packet->flags & SILC_PACKET_FLAG_LIST)
-       break;
-      if (packet->buffer->len < 1)
-       break;
+      /* Verify whether this connection is after all allowed to connect */
+      if (!silc_server_connection_allowed(server, sock, entry->data.conn_type,
+                                         &server->config->param,
+                                         conn->param,
+                                         silc_connauth_get_ske(connauth))) {
+       server->stat.auth_failures++;
+       goto out;
+      }
 
-      status = (SilcStatus)packet->buffer->data[0];
-      if (packet->buffer->len > 1 &&
-         silc_utf8_valid(packet->buffer->data + 1, packet->buffer->len - 1))
-       message = silc_memdup(packet->buffer->data + 1,
-                             packet->buffer->len - 1);
+      /* If we are primary router and we have backup router configured
+        but it has not connected to use yet, do not accept any other
+        connection. */
+      if (server->wait_backup && server->server_type == SILC_ROUTER &&
+         !server->backup_router) {
+       SilcServerConfigRouter *router;
+       router = silc_server_config_get_backup_router(server);
+       if (router && strcmp(server->config->server_info->primary->server_ip,
+                            entry->ip) &&
+           silc_server_find_socket_by_host(server,
+                                           SILC_CONN_SERVER,
+                                           router->backup_replace_ip, 0)) {
+         SILC_LOG_INFO(("Will not accept connections because we do "
+                        "not have backup router connection established"));
+         silc_server_disconnect_remote(server, sock,
+                                       SILC_STATUS_ERR_PERM_DENIED,
+                                       "We do not have connection to backup "
+                                       "router established, try later");
+         server->stat.auth_failures++;
 
-      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
-                    sock->ip, sock->hostname,
-                    silc_get_status_message(status), status,
-                    message ? message : ""));
-      silc_free(message);
+         /* From here on, wait 20 seconds for the backup router to appear. */
+         silc_schedule_task_add_timeout(server->schedule,
+                                        silc_server_backup_router_wait,
+                                        (void *)server, 20, 0);
+         goto out;
+       }
+      }
 
-      /* Do not switch to backup in case of error */
-      server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
+      SILC_LOG_DEBUG(("Remote host is client"));
+      SILC_LOG_INFO(("Connection %s (%s) is client", entry->hostname,
+                    entry->ip));
 
-      /* If backup disconnected then mark that resuming will not be allowed */
-      if (server->server_type == SILC_ROUTER && !server->backup_router &&
-         sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
-       SilcServerEntry server_entry = sock->user_data;
-       if (server_entry->server_type == SILC_BACKUP_ROUTER)
-         server->backup_closed = TRUE;
+      /* Add the client to the client ID cache. The nickname and Client ID
+        and other information is created after we have received NEW_CLIENT
+        packet from client. */
+      client = silc_idlist_add_client(server->local_list,
+                                     NULL, NULL, NULL, NULL, NULL, sock);
+      if (!client) {
+       SILC_LOG_ERROR(("Could not add new client to cache"));
+       server->stat.auth_failures++;
+       silc_server_disconnect_remote(server, sock,
+                                     SILC_STATUS_ERR_AUTH_FAILED, NULL);
+       goto out;
       }
+      entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
 
-      /* Handle the disconnection from our end too */
-      if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
-       silc_server_free_sock_user_data(server, sock, NULL);
-      SILC_SET_DISCONNECTING(sock);
-      silc_server_close_connection(server, sock);
-      server->backup_noswitch = FALSE;
-    }
-    break;
-
-  case SILC_PACKET_SUCCESS:
-    /*
-     * Success received for something. For now we can have only
-     * one protocol for connection executing at once hence this
-     * success message is for whatever protocol is executing currently.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    if (sock->protocol)
-      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-    break;
+      /* Statistics */
+      server->stat.my_clients++;
+      server->stat.clients++;
+      server->stat.cell_clients++;
 
-  case SILC_PACKET_FAILURE:
-    /*
-     * Failure received for something. For now we can have only
-     * one protocol for connection executing at once hence this
-     * failure message is for whatever protocol is executing currently.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
+      /* Get connection parameters */
+      if (conn->param) {
+       param = conn->param;
 
-    /* Check for failure START_USE from backup router */
-    if (server->server_type == SILC_SERVER &&
-       server->backup_primary && packet->buffer->len == 4) {
-      SilcUInt32 type;
-      SILC_GET32_MSB(type, packet->buffer->data);
-      if (type == SILC_SERVER_BACKUP_START_USE) {
-       /* Attempt to reconnect to primary */
-       SILC_LOG_DEBUG(("Received failed START_USE from backup %s", sock->ip));
-
-       /* Default action is to disconnect from backup and reconnect to
-          primary.  Since this failure can happen during switching to
-          backup (backup might have not noticed the primary going down yet),
-          we will wait a while and keep sending START_USE to backup.
-          Only after that we'll give up. */
-       if (server->router == sock->user_data &&
-           (time(0) - server->router_connect) < 30) {
-         SILC_LOG_DEBUG(("Resending START_USE to backup router"));
-         silc_server_backup_send_start_use(server, sock, FALSE);
-         break;
-       }
+       if (!param->keepalive_secs)
+         param->keepalive_secs = server->config->param.keepalive_secs;
 
-       /* If backup is our primary, disconnect now. */
-       if (server->router == sock->user_data) {
-         if (sock->user_data)
-           silc_server_free_sock_user_data(server, sock, NULL);
-         SILC_SET_DISCONNECTING(sock);
-         silc_server_close_connection(server, sock);
+       if (!param->qos && server->config->param.qos) {
+         param->qos = server->config->param.qos;
+         param->qos_rate_limit = server->config->param.qos_rate_limit;
+         param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+         param->qos_limit_sec = server->config->param.qos_limit_sec;
+         param->qos_limit_usec = server->config->param.qos_limit_usec;
        }
 
-       /* Reconnect */
-       silc_server_create_connections(server);
+       /* Check if to be anonymous connection */
+       if (param->anonymous)
+         client->mode |= SILC_UMODE_ANONYMOUS;
       }
-    }
 
-    /* Execute protocol */
-    if (sock->protocol) {
-      sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
-      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      /* Add public key to hash list (for whois using attributes) */
+      if (!silc_hash_table_find_by_context(server->pk_hash,
+                                          entry->data.public_key,
+                                          client, NULL))
+       silc_hash_table_add(server->pk_hash,
+                           entry->data.public_key, client);
+
+      id_entry = (void *)client;
       break;
     }
-    break;
 
-  case SILC_PACKET_REJECT:
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    return;
-    break;
+  case SILC_CONN_SERVER:
+  case SILC_CONN_ROUTER:
+    {
+      SilcServerEntry new_server;
+      SilcBool initiator = FALSE;
+      SilcBool backup_local = FALSE;
+      SilcBool backup_router = FALSE;
+      char *backup_replace_ip = NULL;
+      SilcUInt16 backup_replace_port = 0;
+      SilcServerConfigServer *sconn = entry->sconfig.ref_ptr;
+      SilcServerConfigRouter *rconn = entry->rconfig.ref_ptr;
 
-  case SILC_PACKET_NOTIFY:
-    /*
-     * Received notify packet. Server can receive notify packets from
-     * router. Server then relays the notify messages to clients if needed.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      silc_server_notify_list(server, sock, packet);
-    else
-      silc_server_notify(server, sock, packet);
-    break;
+      /* If we are backup router and this is incoming server connection
+        and we do not have connection to primary router, do not allow
+        the connection. */
+      if (server->server_type == SILC_BACKUP_ROUTER &&
+         entry->data.conn_type == SILC_CONN_SERVER &&
+         !SILC_PRIMARY_ROUTE(server)) {
+       SILC_LOG_INFO(("Will not accept server connection because we do "
+                      "not have primary router connection established"));
+       silc_server_disconnect_remote(server, sock,
+                                     SILC_STATUS_ERR_PERM_DENIED,
+                                     "We do not have connection to primary "
+                                     "router established, try later");
+       server->stat.auth_failures++;
+       goto out;
+      }
 
-    /*
-     * Channel packets
-     */
-  case SILC_PACKET_CHANNEL_MESSAGE:
-    /*
-     * Received channel message. Channel messages are special packets
-     * (although probably most common ones) thus they are handled
-     * specially.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    idata->last_receive = time(NULL);
-    silc_server_channel_message(server, sock, packet);
-    break;
+      if (entry->data.conn_type == SILC_CONN_ROUTER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock,
+                                           entry->data.conn_type,
+                                           &server->config->param,
+                                           rconn ? rconn->param : NULL,
+                                           silc_connauth_get_ske(connauth))) {
+         server->stat.auth_failures++;
+         goto out;
+       }
 
-  case SILC_PACKET_CHANNEL_KEY:
-    /*
-     * Received key for channel. As channels are created by the router
-     * the keys are as well. We will distribute the key to all of our
-     * locally connected clients on the particular channel. Router
-     * never receives this channel and thus is ignored.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_channel_key(server, sock, packet);
-    break;
+       if (rconn) {
+         if (rconn->param) {
+           param = rconn->param;
 
-    /*
-     * Command packets
-     */
-  case SILC_PACKET_COMMAND:
-    /*
-     * Recived command. Processes the command request and allocates the
-     * command context and calls the command.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    server->stat.commands_received++;
-    silc_server_command_process(server, sock, packet);
-    break;
+           if (!param->keepalive_secs)
+             param->keepalive_secs = server->config->param.keepalive_secs;
 
-  case SILC_PACKET_COMMAND_REPLY:
-    /*
-     * Received command reply packet. Received command reply to command. It
-     * may be reply to command sent by us or reply to command sent by client
-     * that we've routed further.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    server->stat.commands_received++;
-    silc_server_command_reply(server, sock, packet);
-    break;
+           if (!param->qos && server->config->param.qos) {
+             param->qos = server->config->param.qos;
+             param->qos_rate_limit = server->config->param.qos_rate_limit;
+             param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+             param->qos_limit_sec = server->config->param.qos_limit_sec;
+             param->qos_limit_usec = server->config->param.qos_limit_usec;
+           }
+         }
 
-    /*
-     * Private Message packets
-     */
-  case SILC_PACKET_PRIVATE_MESSAGE:
-    /*
-     * Received private message packet. The packet is coming from either
-     * client or server.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    idata->last_receive = time(NULL);
-    silc_server_private_message(server, sock, packet);
-    break;
+         initiator = rconn->initiator;
+         backup_local = rconn->backup_local;
+         backup_router = rconn->backup_router;
+         backup_replace_ip = rconn->backup_replace_ip;
+         backup_replace_port = rconn->backup_replace_port;
+       }
+      }
 
-  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
-    /*
-     * Private message key packet.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_private_message_key(server, sock, packet);
-    break;
+      if (entry->data.conn_type == SILC_CONN_SERVER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock,
+                                           entry->data.conn_type,
+                                           &server->config->param,
+                                           sconn ? sconn->param : NULL,
+                                           silc_connauth_get_ske(connauth))) {
+         server->stat.auth_failures++;
+         goto out;
+       }
+       if (sconn) {
+         if (sconn->param) {
+           param = sconn->param;
 
-    /*
-     * Key Exchange protocol packets
-     */
-  case SILC_PACKET_KEY_EXCHANGE:
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
+           if (!param->keepalive_secs)
+             param->keepalive_secs = server->config->param.keepalive_secs;
 
-    if (sock->protocol && sock->protocol->protocol &&
-       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
-      SilcServerKEInternalContext *proto_ctx =
-       (SilcServerKEInternalContext *)sock->protocol->context;
+           if (!param->qos && server->config->param.qos) {
+             param->qos = server->config->param.qos;
+             param->qos_rate_limit = server->config->param.qos_rate_limit;
+             param->qos_bytes_limit = server->config->param.qos_bytes_limit;
+             param->qos_limit_sec = server->config->param.qos_limit_sec;
+             param->qos_limit_usec = server->config->param.qos_limit_usec;
+           }
+         }
 
-      proto_ctx->packet = silc_packet_context_dup(packet);
+         backup_router = sconn->backup_router;
+       }
+      }
 
-      /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->schedule, 0, 100000);
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
-                     "protocol active (%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")));
-    }
-    break;
+      /* If we are primary router and we have backup router configured
+        but it has not connected to use yet, do not accept any other
+        connection. */
+#if 0
+      if (server->wait_backup && server->server_type == SILC_ROUTER &&
+         !server->backup_router && !backup_router) {
+       SilcServerConfigRouter *router;
+       router = silc_server_config_get_backup_router(server);
+       if (router && strcmp(server->config->server_info->primary->server_ip,
+                            ip) &&
+           silc_server_find_socket_by_host(server,
+                                           SILC_CONN_SERVER,
+                                           router->backup_replace_ip, 0)) {
+         SILC_LOG_INFO(("Will not accept connections because we do "
+                        "not have backup router connection established"));
+         silc_server_disconnect_remote(server, sock,
+                                       SILC_STATUS_ERR_PERM_DENIED,
+                                       "We do not have connection to backup "
+                                       "router established, try later");
+         server->stat.auth_failures++;
 
-  case SILC_PACKET_KEY_EXCHANGE_1:
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
+         /* From here on, wait 20 seconds for the backup router to appear. */
+         silc_schedule_task_add_timeout(server->schedule,
+                                        silc_server_backup_router_wait,
+                                        (void *)server, 20, 0);
+         goto out;
+       }
+      }
+#endif /* 0 */
+
+      SILC_LOG_DEBUG(("Remote host is %s",
+                     entry->data.conn_type == SILC_CONN_SERVER ?
+                     "server" : (backup_router ?
+                                 "backup router" : "router")));
+      SILC_LOG_INFO(("Connection %s (%s) is %s", entry->hostname,
+                    entry->ip, entry->data.conn_type == SILC_CONN_SERVER ?
+                    "server" : (backup_router ?
+                                "backup router" : "router")));
+
+      /* Add the server into server cache. The server name and Server ID
+        is updated after we have received NEW_SERVER packet from the
+        server. We mark ourselves as router for this server if we really
+        are router. */
+      new_server =
+       silc_idlist_add_server((entry->data.conn_type == SILC_CONN_SERVER ?
+                               server->local_list : (backup_router ?
+                                                     server->local_list :
+                                                     server->global_list)),
+                              NULL,
+                              (entry->data.conn_type == SILC_CONN_SERVER ?
+                               SILC_SERVER : SILC_ROUTER),
+                              NULL,
+                              (entry->data.conn_type == SILC_CONN_SERVER ?
+                               server->id_entry : (backup_router ?
+                                                   server->id_entry : NULL)),
+                              sock);
+      if (!new_server) {
+       SILC_LOG_ERROR(("Could not add new server to cache"));
+       silc_server_disconnect_remote(server, sock,
+                                     SILC_STATUS_ERR_AUTH_FAILED, NULL);
+       server->stat.auth_failures++;
+       goto out;
+      }
+      entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
 
-    if (sock->protocol && sock->protocol->protocol &&
-       (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
-        sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
+      id_entry = (void *)new_server;
 
-      if (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
-       SilcServerRekeyInternalContext *proto_ctx =
-         (SilcServerRekeyInternalContext *)sock->protocol->context;
+      /* If the incoming connection is router and marked as backup router
+        then add it to be one of our backups */
+      if (entry->data.conn_type == SILC_CONN_ROUTER && backup_router) {
+       /* Change it back to SERVER type since that's what it really is. */
+       if (backup_local)
+         entry->data.conn_type = SILC_CONN_SERVER;
+       new_server->server_type = SILC_BACKUP_ROUTER;
 
-       if (proto_ctx->packet)
-         silc_packet_context_free(proto_ctx->packet);
+       SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
+                              ("Backup router %s is now online",
+                               entry->hostname));
 
-       proto_ctx->packet = silc_packet_context_dup(packet);
+       /* Remove the backup waiting with timeout */
+       silc_schedule_task_add_timeout(server->schedule,
+                                      silc_server_backup_router_wait,
+                                      (void *)server, 10, 0);
+      }
 
-       /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      /* Statistics */
+      if (entry->data.conn_type == SILC_CONN_SERVER) {
+       server->stat.my_servers++;
+       server->stat.servers++;
       } else {
-       SilcServerKEInternalContext *proto_ctx =
-         (SilcServerKEInternalContext *)sock->protocol->context;
-
-       if (proto_ctx->packet)
-         silc_packet_context_free(proto_ctx->packet);
+       server->stat.my_routers++;
+       server->stat.routers++;
+      }
 
-       proto_ctx->packet = silc_packet_context_dup(packet);
-       proto_ctx->dest_id_type = packet->src_id_type;
-       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
-                                           packet->src_id_type);
-       if (!proto_ctx->dest_id)
+      /* Check whether this connection is to be our primary router connection
+        if we do not already have the primary route. */
+      if (!backup_router &&
+         server->standalone && entry->data.conn_type == SILC_CONN_ROUTER) {
+       if (silc_server_config_is_primary_route(server) && !initiator)
          break;
 
-       /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->schedule,
-                             0, 100000);
+       SILC_LOG_DEBUG(("We are not standalone server anymore"));
+       server->standalone = FALSE;
+       if (!server->id_entry->router) {
+         server->id_entry->router = id_entry;
+         server->router = id_entry;
+       }
       }
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
-                     "protocol active (%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")));
-    }
-    break;
 
-  case SILC_PACKET_KEY_EXCHANGE_2:
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
+    }
 
-    if (sock->protocol && sock->protocol->protocol &&
-       (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
-        sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
-
-      if (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
-       SilcServerRekeyInternalContext *proto_ctx =
-         (SilcServerRekeyInternalContext *)sock->protocol->context;
-
-       if (proto_ctx->packet)
-         silc_packet_context_free(proto_ctx->packet);
-
-       proto_ctx->packet = silc_packet_context_dup(packet);
+  default:
+    goto out;
+    break;
+  }
 
-       /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-      } else {
-       SilcServerKEInternalContext *proto_ctx =
-         (SilcServerKEInternalContext *)sock->protocol->context;
+  /* Add the common data structure to the ID entry. */
+  silc_idlist_add_data(id_entry, (SilcIDListData)entry);
+  silc_packet_set_context(sock, id_entry);
 
-       if (proto_ctx->packet)
-         silc_packet_context_free(proto_ctx->packet);
+  /* Connection has been fully established now. Everything is ok. */
+  SILC_LOG_DEBUG(("New connection authenticated"));
 
-       proto_ctx->packet = silc_packet_context_dup(packet);
-       proto_ctx->dest_id_type = packet->src_id_type;
-       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
-                                           packet->src_id_type);
-       if (!proto_ctx->dest_id)
-         break;
+  /* XXX Add connection to server->conns so that we know we have connection
+     to this peer. */
+  /* XXX */
 
-       /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->schedule,
-                             0, 100000);
-      }
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
-                     "protocol active (%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")));
-    }
-    break;
+#if 0
+  /* Perform keepalive. */
+  if (param->keepalive_secs)
+    silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
+                             silc_server_perform_heartbeat,
+                             server->schedule);
 
-  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
-    /*
-     * Connection authentication request packet. When we receive this packet
-     * we will send to the other end information about our mandatory
-     * authentication method for the connection. This packet maybe received
-     * at any time.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_connection_auth_request(server, sock, packet);
-    break;
+  /* Perform Quality of Service */
+  if (param->qos)
+    silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit,
+                       param->qos_limit_sec, param->qos_limit_usec,
+                       server->schedule);
+#endif
 
-    /*
-     * Connection Authentication protocol packets
-     */
-  case SILC_PACKET_CONNECTION_AUTH:
-    /* Start of the authentication protocol. We receive here the
-       authentication data and will verify it. */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
+  silc_server_config_unref(&entry->cconfig);
+  silc_server_config_unref(&entry->sconfig);
+  silc_server_config_unref(&entry->rconfig);
+  silc_free(entry);
 
-    if (sock->protocol && sock->protocol->protocol->type
-       == SILC_PROTOCOL_SERVER_CONNECTION_AUTH) {
+ out:
+  silc_ske_free(silc_connauth_get_ske(connauth));
+  silc_connauth_free(connauth);
+}
 
-      SilcServerConnAuthInternalContext *proto_ctx =
-       (SilcServerConnAuthInternalContext *)sock->protocol->context;
+/* SKE completion callback.  We set the new keys into use here. */
 
-      proto_ctx->packet = silc_packet_context_dup(packet);
+static void
+silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status,
+                            SilcSKESecurityProperties prop,
+                            SilcSKEKeyMaterial keymat,
+                            SilcSKERekeyMaterial rekey,
+                            void *context)
+{
+  SilcPacketStream sock = context;
+  SilcUnknownEntry entry = silc_packet_get_context(sock);
+  SilcServer server = entry->server;
+  SilcConnAuth connauth;
+  SilcCipher send_key, receive_key;
+  SilcHmac hmac_send, hmac_receive;
+  SilcHash hash;
+
+  if (status != SILC_SKE_STATUS_OK) {
+    /* SKE failed */
+    SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
+                   silc_ske_map_status(status), entry->hostname, entry->ip));
+    silc_ske_free(ske);
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+    return;
+  }
 
-      /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-    } else {
-      SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
-                     "protocol active (%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")));
-    }
-    break;
+  SILC_LOG_DEBUG(("Setting keys into use"));
 
-  case SILC_PACKET_NEW_ID:
-    /*
-     * Received New ID packet. This includes some new ID that has been
-     * created. It may be for client, server or channel. This is the way
-     * to distribute information about new registered entities in the
-     * SILC network.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      silc_server_new_id_list(server, sock, packet);
-    else
-      silc_server_new_id(server, sock, packet);
-    break;
+  /* Set the keys into use.  The data will be encrypted after this. */
+  if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
+                        &hmac_send, &hmac_receive, &hash)) {
+    /* Error setting keys */
+    silc_ske_free(ske);
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+    return;
+  }
+  silc_packet_set_keys(sock, send_key, receive_key, hmac_send,
+                      hmac_receive, FALSE);
 
-  case SILC_PACKET_NEW_CLIENT:
-    /*
-     * Received new client packet. This includes client information that
-     * we will use to create initial client ID. After creating new
-     * ID we will send it to the client.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_new_client(server, sock, packet);
-    break;
+  SILC_LOG_DEBUG(("Starting connection authentication"));
+  server->stat.auth_attempts++;
 
-  case SILC_PACKET_NEW_SERVER:
-    /*
-     * Received new server packet. This includes Server ID and some other
-     * information that we may save. This is received after server has
-     * connected to us.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_new_server(server, sock, packet);
-    break;
+  connauth = silc_connauth_alloc(server->schedule, ske,
+                                server->config->conn_auth_timeout);
+  if (!connauth) {
+    /** Error allocating auth protocol */
+    silc_ske_free(ske);
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+    return;
+  }
 
-  case SILC_PACKET_NEW_CHANNEL:
-    /*
-     * Received new channel packet. Information about new channel in the
-     * network are distributed using this packet.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      silc_server_new_channel_list(server, sock, packet);
-    else
-      silc_server_new_channel(server, sock, packet);
-    break;
+  /* Start connection authentication */
+  silc_connauth_responder(connauth, silc_server_accept_get_auth,
+                         silc_server_accept_auth_compl, sock);
+}
 
-  case SILC_PACKET_HEARTBEAT:
-    /*
-     * Received heartbeat.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    break;
+/* Accept new TCP connection */
 
-  case SILC_PACKET_KEY_AGREEMENT:
-    /*
-     * Received heartbeat.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_key_agreement(server, sock, packet);
-    break;
+static void silc_server_accept_new_connection(SilcNetStatus status,
+                                             SilcStream stream,
+                                             void *context)
+{
+  SilcServer server = context;
+  SilcPacketStream packet_stream;
+  SilcServerConfigClient *cconfig = NULL;
+  SilcServerConfigServer *sconfig = NULL;
+  SilcServerConfigRouter *rconfig = NULL;
+  SilcServerConfigDeny *deny;
+  SilcUnknownEntry entry;
+  SilcSKE ske;
+  SilcSKEParamsStruct params;
+  char *hostname, *ip;
+  SilcUInt16 port;
 
-  case SILC_PACKET_REKEY:
-    /*
-     * Received re-key packet. The sender wants to regenerate the session
-     * keys.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_rekey(server, sock, packet);
-    break;
+  SILC_LOG_DEBUG(("Accepting new connection"));
 
-  case SILC_PACKET_REKEY_DONE:
-    /*
-     * The re-key is done.
-     */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
+  /* Check for maximum allowed connections */
+  server->stat.conn_attempts++;
+#if 0
+  if (silc_server_num_connections(server) >
+      server->config->param.connections_max) {
+    SILC_LOG_ERROR(("Refusing connection, server is full"));
+    server->stat.conn_failures++;
+    silc_stream_destroy(stream);
+    return;
+  }
+#endif
 
-    if (sock->protocol && sock->protocol->protocol &&
-       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
+  /* Get hostname, IP and port */
+  if (!silc_socket_stream_get_info(stream, NULL, (const char **)&hostname,
+                                  (const char **)&ip, &port)) {
+    /* Bad socket stream */
+    server->stat.conn_failures++;
+    silc_stream_destroy(stream);
+    return;
+  }
 
-      SilcServerRekeyInternalContext *proto_ctx =
-       (SilcServerRekeyInternalContext *)sock->protocol->context;
+  /* Create packet stream */
+  packet_stream = silc_packet_stream_create(server->packet_engine,
+                                           server->schedule, stream);
+  if (!packet_stream) {
+    SILC_LOG_ERROR(("Refusing connection, cannot create packet stream"));
+    server->stat.conn_failures++;
+    silc_stream_destroy(stream);
+    return;
+  }
+  server->stat.conn_num++;
 
-      if (proto_ctx->packet)
-       silc_packet_context_free(proto_ctx->packet);
+  /* Set source ID to packet stream */
+  if (!silc_packet_set_ids(packet_stream, SILC_ID_SERVER, &server->id,
+                          0, NULL)) {
+    /* Out of memory */
+    server->stat.conn_failures++;
+    silc_packet_stream_destroy(packet_stream);
+    return;
+  }
 
-      proto_ctx->packet = silc_packet_context_dup(packet);
+  /* Check whether this connection is denied to connect to us. */
+  deny = silc_server_config_find_denied(server, ip);
+  if (!deny)
+    deny = silc_server_config_find_denied(server, hostname);
+  if (deny) {
+    /* The connection is denied */
+    SILC_LOG_INFO(("Connection %s (%s) is denied", hostname, ip));
+    silc_server_disconnect_remote(server, packet_stream,
+                                 SILC_STATUS_ERR_BANNED_FROM_SERVER,
+                                 deny->reason);
+    return;
+  }
 
-      /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-    } else {
-      SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
-                     "protocol active (%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")));
-    }
-    break;
+  /* Check whether we have configured this sort of connection at all. We
+     have to check all configurations since we don't know what type of
+     connection this is. */
+  if (!(cconfig = silc_server_config_find_client(server, ip)))
+    cconfig = silc_server_config_find_client(server, hostname);
+  if (!(sconfig = silc_server_config_find_server_conn(server, ip)))
+    sconfig = silc_server_config_find_server_conn(server, hostname);
+  if (server->server_type == SILC_ROUTER)
+    if (!(rconfig = silc_server_config_find_router_conn(server, ip, port)))
+      rconfig = silc_server_config_find_router_conn(server, hostname, port);
+  if (!cconfig && !sconfig && !rconfig) {
+    SILC_LOG_INFO(("Connection %s (%s) is not allowed", hostname, ip));
+    server->stat.conn_failures++;
+    silc_server_disconnect_remote(server, packet_stream,
+                                 SILC_STATUS_ERR_BANNED_FROM_SERVER, NULL);
+    return;
+  }
 
-  case SILC_PACKET_FTP:
-    /* FTP packet */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_ftp(server, sock, packet);
-    break;
+  /* The connection is allowed */
+  entry = silc_calloc(1, sizeof(*entry));
+  if (!entry) {
+    server->stat.conn_failures++;
+    silc_server_disconnect_remote(server, packet_stream,
+                                 SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+    return;
+  }
+  entry->hostname = hostname;
+  entry->ip = ip;
+  entry->port = port;
+  entry->server = server;
+  silc_packet_set_context(packet_stream, entry);
 
-  case SILC_PACKET_RESUME_CLIENT:
-    /* Resume client */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_resume_client(server, sock, packet);
-    break;
+  silc_server_config_ref(&entry->cconfig, server->config, cconfig);
+  silc_server_config_ref(&entry->sconfig, server->config, sconfig);
+  silc_server_config_ref(&entry->rconfig, server->config, rconfig);
 
-  case SILC_PACKET_RESUME_ROUTER:
-    /* Resume router packet received. This packet is received for backup
-       router resuming protocol. */
-    if (packet->flags & SILC_PACKET_FLAG_LIST)
-      break;
-    silc_server_backup_resume_router(server, sock, packet);
-    break;
+  /* Take flags for key exchange. Since we do not know what type of connection
+     this is, we go through all found configurations and use the global ones
+     as well. This will result always into strictest key exchange flags. */
+  memset(&params, 0, sizeof(params));
+  SILC_GET_SKE_FLAGS(cconfig, params.flags);
+  SILC_GET_SKE_FLAGS(sconfig, params.flags);
+  SILC_GET_SKE_FLAGS(rconfig, params.flags);
+  if (server->config->param.key_exchange_pfs)
+    params.flags |= SILC_SKE_SP_FLAG_PFS;
 
-  default:
-    SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
-    break;
+  SILC_LOG_INFO(("Incoming connection %s (%s)", hostname, ip));
+  server->stat.conn_attempts++;
+
+  /* Start SILC Key Exchange protocol */
+  SILC_LOG_DEBUG(("Starting key exchange protocol"));
+  ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
+                      server->public_key, server->private_key,
+                      packet_stream);
+  if (!ske) {
+    server->stat.conn_failures++;
+    silc_server_disconnect_remote(server, packet_stream,
+                                 SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+    return;
   }
+  silc_ske_set_callbacks(ske, silc_server_verify_key,
+                        silc_server_accept_completed, packet_stream);
+
+  /* Start key exchange protocol */
+  params.version = silc_version_string;
+  params.timeout_secs = server->config->key_exchange_timeout;
+  silc_ske_responder(ske, packet_stream, &params);
 }
 
-/* Creates connection to a remote router. */
 
-void silc_server_create_connection(SilcServer server,
-                                  const char *remote_host, SilcUInt32 port)
+/********************************** Rekey ***********************************/
+
+/* Initiator rekey completion callback */
+
+static void silc_server_rekey_completion(SilcSKE ske,
+                                        SilcSKEStatus status,
+                                        const SilcSKESecurityProperties prop,
+                                        const SilcSKEKeyMaterial keymat,
+                                        SilcSKERekeyMaterial rekey,
+                                        void *context)
 {
-  SilcServerConnection sconn;
+  SilcPacketStream sock = context;
+  SilcIDListData idata = silc_packet_get_context(sock);
+  SilcServer server = idata->sconn->server;
+
+  idata->sconn->op = NULL;
+  if (status != SILC_SKE_STATUS_OK) {
+    SILC_LOG_ERROR(("Error during rekey protocol with %s",
+                   idata->sconn->remote_host));
+    return;
+  }
 
-  /* Allocate connection object for hold connection specific stuff. */
-  sconn = silc_calloc(1, sizeof(*sconn));
-  sconn->remote_host = strdup(remote_host);
-  sconn->remote_port = port;
-  sconn->no_reconnect = TRUE;
+  SILC_LOG_DEBUG(("Rekey protocol completed with %s:%d [%s]",
+                 idata->sconn->remote_host, idata->sconn->remote_port,
+                 SILC_CONNTYPE_STRING(idata->conn_type)));
 
-  silc_schedule_task_add(server->schedule, 0,
-                        silc_server_connect_router,
-                        (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  /* Save rekey data for next rekey */
+  idata->rekey = rekey;
+
+  /* Register new rekey timeout */
+  silc_schedule_task_add_timeout(server->schedule, silc_server_do_rekey,
+                                sock, idata->sconn->rekey_timeout, 0);
 }
 
-SILC_TASK_CALLBACK(silc_server_close_connection_final)
+/* Rekey callback.  Start rekey as initiator */
+
+SILC_TASK_CALLBACK(silc_server_do_rekey)
 {
   SilcServer server = app_context;
-  SilcSocketConnection sock = context;
+  SilcPacketStream sock = context;
+  SilcIDListData idata = silc_packet_get_context(sock);
+  SilcSKE ske;
 
-  SILC_LOG_DEBUG(("Deleting socket %p", sock));
+  /* Do not execute rekey with disabled connections */
+  if (idata->status & SILC_IDLIST_STATUS_DISABLED)
+    return;
 
-  /* Close the actual connection */
-  silc_net_close_connection(sock->sock);
-  server->sockets[sock->sock] = NULL;
-  server->stat.conn_num--;
+  /* If another protocol is active do not start rekey */
+  if (idata->sconn->op) {
+    SILC_LOG_DEBUG(("Waiting for other protocol to finish before rekeying"));
+    silc_schedule_task_add_timeout(server->schedule, silc_server_do_rekey,
+                                  sock, 60, 0);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]",
+                 idata->sconn->remote_host, idata->sconn->remote_port,
+                 SILC_CONNTYPE_STRING(idata->conn_type)));
+
+  /* Allocate SKE */
+  ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
+                      server->public_key, server->private_key, sock);
+  if (!ske)
+    return;
+
+  /* Set SKE callbacks */
+  silc_ske_set_callbacks(ske, NULL, silc_server_rekey_completion, sock);
 
-  /* We won't listen for this connection anymore */
-  silc_schedule_task_del_by_fd(server->schedule, sock->sock);
-  silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+  /* Perform rekey */
+  idata->sconn->op = silc_ske_rekey_initiator(ske, sock, idata->rekey);
+}
+
+
+/****************************** Disconnection *******************************/
+
+/* Destroys packet stream. */
 
-  silc_socket_free(sock);
+SILC_TASK_CALLBACK(silc_server_close_connection_final)
+{
+  silc_packet_stream_destroy(context);
 }
 
 /* Closes connection to socket connection */
 
 void silc_server_close_connection(SilcServer server,
-                                 SilcSocketConnection sock)
+                                 SilcPacketStream sock)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   char tmp[128];
+  const char *hostname;
+  SilcUInt16 port;
 
-  if (SILC_IS_DISCONNECTED(sock)) {
-    silc_schedule_task_del_by_fd(server->schedule, sock->sock);
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_close_connection_final,
-                          (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-    server->sockets[sock->sock] = NULL;
-    return;
-  }
-
+#if 0
   /* If any protocol is active cancel its execution. It will call
      the final callback which will finalize the disconnection. */
   if (sock->protocol && sock->protocol->protocol &&
@@ -3264,112 +2654,76 @@ void silc_server_close_connection(SilcServer server,
     sock->protocol = NULL;
     return;
   }
+#endif
 
   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"), tmp[0] ? tmp : ""));
-
-  SILC_SET_DISCONNECTED(sock);
-  silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_close_connection_final,
-                        (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
-  server->sockets[sock->sock] = NULL;
+  //  silc_socket_get_error(sock, tmp, sizeof(tmp));
+  silc_socket_stream_get_info(sock, NULL, &hostname, NULL, &port);
+  SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", hostname, port,
+                SILC_CONNTYPE_STRING(idata->conn_type),
+                tmp[0] ? tmp : ""));
+
+  //  silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
+
+  /* Close connection with timeout */
+  server->stat.conn_num--;
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_close_connection_final,
+                                sock, 0, 1);
 }
 
 /* Sends disconnect message to remote connection and disconnects the
-   connection.  NOTE: If this is called from protocol callback
-   then sock->protocol must be set NULL before calling this, since
-   this routine dispatches protocol callbacks too. */
+   connection. */
 
 void silc_server_disconnect_remote(SilcServer server,
-                                  SilcSocketConnection sock,
+                                  SilcPacketStream sock,
                                   SilcStatus status, ...)
 {
-  va_list ap;
   unsigned char buf[512];
-  SilcBuffer buffer;
+  va_list ap;
   char *cp;
-  int len;
 
   if (!sock)
     return;
 
-  if (SILC_IS_DISCONNECTING(sock)) {
-    SILC_SET_DISCONNECTED(sock);
-    silc_server_close_connection(server, sock);
-    return;
-  }
+  SILC_LOG_DEBUG(("Disconnecting remote host"));
 
-  memset(buf, 0, sizeof(buf));
   va_start(ap, status);
   cp = va_arg(ap, char *);
-  if (cp) {
-    vsnprintf(buf, sizeof(buf) - 1, cp, ap);
-    cp = buf;
-  }
-  va_end(ap);
-
-  SILC_LOG_DEBUG(("Disconnecting remote host"));
-
-  /* Notify remote end that the conversation is over. The notify message
-     is tried to be sent immediately. */
-
-  len = 1;
-  if (cp)
-    len += silc_utf8_encoded_len(buf, strlen(buf), SILC_STRING_ASCII);
-
-  buffer = silc_buffer_alloc_size(len);
-  if (!buffer)
-    goto out;
-
-  buffer->data[0] = status;
   if (cp)
-    silc_utf8_encode(buf, strlen(buf), SILC_STRING_ASCII, buffer->data + 1,
-                    buffer->len - 1);
-  silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,
-                         buffer->data, buffer->len, TRUE);
-  silc_buffer_free(buffer);
+    silc_vsnprintf(buf, sizeof(buf), cp, ap);
+  va_end(ap);
 
- out:
-  silc_server_packet_queue_purge(server, sock);
+  /* Send SILC_PACKET_DISCONNECT */
+  silc_packet_send_va(sock, SILC_PACKET_DISCONNECT, 0,
+                     SILC_STR_UI_CHAR(status),
+                     SILC_STR_UI8_STRING(cp ? buf : NULL),
+                     SILC_STR_END);
 
-  /* Mark the connection to be disconnected */
-  SILC_SET_DISCONNECTING(sock);
+  /* Close connection */
   silc_server_close_connection(server, sock);
 }
 
 SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
 {
-  SilcServer server = app_context;
   SilcClientEntry client = context;
 
   assert(!silc_hash_table_count(client->channels));
 
   silc_idlist_del_data(client);
-  silc_idcache_purge_by_context(server->local_list->clients, client);
+  //  silc_idcache_purge_by_context(server->local_list->clients, client);
 }
 
 /* Frees client data and notifies about client's signoff. */
 
 void silc_server_free_client_data(SilcServer server,
-                                 SilcSocketConnection sock,
+                                 SilcPacketStream sock,
                                  SilcClientEntry client,
                                  int notify,
                                  const char *signoff)
 {
   SILC_LOG_DEBUG(("Freeing client data"));
 
-  /* If there is pending outgoing data for the client then purge it
-     to the network before removing the client entry. */
-  silc_server_packet_queue_purge(server, sock);
-
   if (client->id) {
     /* Check if anyone is watching this nickname */
     if (server->server_type == SILC_ROUTER)
@@ -3412,10 +2766,9 @@ void silc_server_free_client_data(SilcServer server,
      into history (for WHOWAS command) for 5 minutes, unless we're
      shutting down server. */
   if (!server->server_shutdown) {
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_free_client_data_timeout,
-                          client, 600, 0,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_free_client_data_timeout,
+                                  client, 600, 0);
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
     client->mode = 0;
@@ -3433,34 +2786,27 @@ void silc_server_free_client_data(SilcServer server,
    entities. */
 
 void silc_server_free_sock_user_data(SilcServer server,
-                                    SilcSocketConnection sock,
+                                    SilcPacketStream sock,
                                     const char *signoff_message)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
 
-  /* If any protocol is active cancel its execution */
-  if (sock->protocol && sock->protocol->protocol &&
-      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
-    SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
-    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;
-    if (!sock->user_data)
-      return;
-  }
+  if (!idata)
+    return;
 
-  switch (sock->type) {
-  case SILC_SOCKET_TYPE_CLIENT:
+  switch (idata->conn_type) {
+  case SILC_CONN_CLIENT:
     {
-      SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
-      silc_server_free_client_data(server, sock, user_data, TRUE,
+      SilcClientEntry client_entry = (SilcClientEntry)idata;
+      silc_server_free_client_data(server, sock, client_entry, TRUE,
                                   signoff_message);
       break;
     }
-  case SILC_SOCKET_TYPE_SERVER:
-  case SILC_SOCKET_TYPE_ROUTER:
+
+  case SILC_CONN_SERVER:
+  case SILC_CONN_ROUTER:
     {
-      SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
+      SilcServerEntry user_data = (SilcServerEntry)idata;
       SilcServerEntry backup_router = NULL;
 
       SILC_LOG_DEBUG(("Freeing server data"));
@@ -3470,7 +2816,7 @@ void silc_server_free_sock_user_data(SilcServer server,
 
       if (!server->backup_router && server->server_type == SILC_ROUTER &&
          backup_router == server->id_entry &&
-         sock->type != SILC_SOCKET_TYPE_ROUTER)
+         idata->conn_type != SILC_CONN_ROUTER)
        backup_router = NULL;
 
       if (server->server_shutdown || server->backup_noswitch)
@@ -3512,6 +2858,7 @@ void silc_server_free_sock_user_data(SilcServer server,
          /* We stop here to take a breath */
          sleep(2);
 
+#if 0
          if (server->backup_router) {
            server->server_type = SILC_ROUTER;
 
@@ -3521,6 +2868,7 @@ void silc_server_free_sock_user_data(SilcServer server,
                                         silc_server_backup_connected,
                                         NULL);
          }
+#endif /* 0 */
 
          /* Mark this connection as replaced */
          silc_server_backup_replaced_add(server, user_data->id,
@@ -3534,7 +2882,7 @@ void silc_server_free_sock_user_data(SilcServer server,
        silc_server_backup_replaced_add(server, user_data->id,
                                        backup_router);
       } else if (server->server_type == SILC_SERVER &&
-                sock->type == SILC_SOCKET_TYPE_ROUTER) {
+                idata->conn_type == SILC_CONN_ROUTER) {
        /* Reconnect to the router (backup) */
        if (!server->no_reconnect)
          silc_server_create_connections(server);
@@ -3555,7 +2903,7 @@ void silc_server_free_sock_user_data(SilcServer server,
           coming from the primary router, so mark that as the owner
           of this entry. */
        if (server->server_type == SILC_BACKUP_ROUTER &&
-           sock->type == SILC_SOCKET_TYPE_SERVER)
+           sock->type == SILC_CONN_SERVER)
          silc_server_remove_clients_by_server(server, server->router,
                                               user_data, TRUE);
        else
@@ -3618,7 +2966,7 @@ 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);
-      if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+      if (idata->conn_type == SILC_CONN_SERVER) {
        server->stat.my_servers--;
        server->stat.servers--;
       } else {
@@ -3643,19 +2991,18 @@ void silc_server_free_sock_user_data(SilcServer server,
       }
       break;
     }
+
   default:
     {
-      SilcUnknownEntry user_data = (SilcUnknownEntry)sock->user_data;
+      SilcUnknownEntry entry = (SilcUnknownEntry)idata;
 
       SILC_LOG_DEBUG(("Freeing unknown connection data"));
 
-      silc_idlist_del_data(user_data);
-      silc_free(user_data);
+      silc_idlist_del_data(idata);
+      silc_free(entry);
       break;
     }
   }
-
-  sock->user_data = NULL;
 }
 
 /* Removes client from all channels it has joined. This is used when client
@@ -3663,12 +3010,12 @@ void silc_server_free_sock_user_data(SilcServer server,
    channel is removed as well. This sends the SIGNOFF notify types. */
 
 void silc_server_remove_from_channels(SilcServer server,
-                                     SilcSocketConnection sock,
+                                     SilcPacketStream sock,
                                      SilcClientEntry client,
-                                     bool notify,
+                                     SilcBool notify,
                                      const char *signoff_message,
-                                     bool keygen,
-                                     bool killed)
+                                     SilcBool keygen,
+                                     SilcBool killed)
 {
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
@@ -3735,7 +3082,7 @@ void silc_server_remove_from_channels(SilcServer server,
        silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                           SILC_NOTIFY_TYPE_SIGNOFF,
                                           signoff_message ? 2 : 1,
-                                          clidp->data, clidp->len,
+                                          clidp->data, silc_buffer_len(clidp),
                                           signoff_message, signoff_message ?
                                           strlen(signoff_message) : 0);
 
@@ -3749,7 +3096,7 @@ void silc_server_remove_from_channels(SilcServer server,
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_SIGNOFF,
                                         signoff_message ? 2 : 1,
-                                        clidp->data, clidp->len,
+                                        clidp->data, silc_buffer_len(clidp),
                                         signoff_message, signoff_message ?
                                         strlen(signoff_message) : 0);
 
@@ -3760,8 +3107,8 @@ void silc_server_remove_from_channels(SilcServer server,
        SilcBuffer ab;
        SilcArgumentPayload iargs;
        ab = silc_argument_payload_encode_one(NULL, clidp->data,
-                                             clidp->len, 3);
-       iargs = silc_argument_payload_parse(ab->data, ab->len, 1);
+                                             silc_buffer_len(clidp), 3);
+       iargs = silc_argument_payload_parse(ab->data, silc_buffer_len(ab), 1);
        silc_server_inviteban_process(server, channel->invite_list, 1, iargs);
        silc_buffer_free(ab);
        silc_argument_payload_free(iargs);
@@ -3796,11 +3143,11 @@ void silc_server_remove_from_channels(SilcServer server,
    last client leaves the channel. If `notify' is FALSE notify messages
    are not sent. */
 
-bool silc_server_remove_from_one_channel(SilcServer server,
-                                        SilcSocketConnection sock,
+SilcBool silc_server_remove_from_one_channel(SilcServer server,
+                                        SilcPacketStream sock,
                                         SilcChannelEntry channel,
                                         SilcClientEntry client,
-                                        bool notify)
+                                        SilcBool notify)
 {
   SilcChannelClientEntry chl;
   SilcBuffer clidp;
@@ -3856,7 +3203,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
     if (notify && channel->global_users)
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_LEAVE, 1,
-                                        clidp->data, clidp->len);
+                                        clidp->data, silc_buffer_len(clidp));
 
     silc_schedule_task_del_by_context(server->schedule, channel->rekey);
     silc_server_channel_delete(server, channel);
@@ -3868,12 +3215,13 @@ bool silc_server_remove_from_one_channel(SilcServer server,
   if (notify)
     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                       SILC_NOTIFY_TYPE_LEAVE, 1,
-                                      clidp->data, clidp->len);
+                                      clidp->data, silc_buffer_len(clidp));
 
   silc_buffer_free(clidp);
   return TRUE;
 }
 
+#if 0
 /* Timeout callback. This is called if connection is idle or for some
    other reason is not responding within some period of time. This
    disconnects the remote end. */
@@ -3881,8 +3229,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
 SILC_TASK_CALLBACK(silc_server_timeout_remote)
 {
   SilcServer server = (SilcServer)context;
-  SilcSocketConnection sock = server->sockets[fd];
-  SilcProtocolType protocol = 0;
+  SilcPacketStream sock = server->sockets[fd];
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -3914,6 +3261,7 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
   if (sock->user_data)
     silc_server_free_sock_user_data(server, sock, NULL);
 }
+#endif /* 0 */
 
 /* Creates new channel. Sends NEW_CHANNEL packet to primary route. This
    function may be used only by router. In real SILC network all channels
@@ -3929,7 +3277,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
 {
   SilcChannelID *channel_id;
   SilcChannelEntry entry;
-  SilcCipher key;
+  SilcCipher send_key, receive_key;
   SilcHmac newhmac;
 
   SILC_LOG_DEBUG(("Creating new channel %s", channel_name));
@@ -3940,12 +3288,17 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
     hmac = SILC_DEFAULT_HMAC;
 
   /* Allocate cipher */
-  if (!silc_cipher_alloc(cipher, &key))
+  if (!silc_cipher_alloc(cipher, &send_key))
     return NULL;
+  if (!silc_cipher_alloc(cipher, &receive_key)) {
+    silc_cipher_free(send_key);
+    return NULL;
+  }
 
   /* Allocate hmac */
   if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
-    silc_cipher_free(key);
+    silc_cipher_free(send_key);
+    silc_cipher_free(receive_key);
     return NULL;
   }
 
@@ -3955,7 +3308,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   if (!silc_id_create_channel_id(server, router_id, server->rng,
                                 &channel_id)) {
     silc_free(channel_name);
-    silc_cipher_free(key);
+    silc_cipher_free(send_key);
+    silc_cipher_free(receive_key);
     silc_hmac_free(newhmac);
     return NULL;
   }
@@ -3963,10 +3317,11 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   /* Create the channel */
   entry = silc_idlist_add_channel(server->local_list, channel_name,
                                  SILC_CHANNEL_MODE_NONE, channel_id,
-                                 NULL, key, newhmac, 0);
+                                 NULL, send_key, receive_key, newhmac);
   if (!entry) {
     silc_free(channel_name);
-    silc_cipher_free(key);
+    silc_cipher_free(send_key);
+    silc_cipher_free(receive_key);
     silc_hmac_free(newhmac);
     silc_free(channel_id);
     return NULL;
@@ -3977,7 +3332,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
 
   /* Now create the actual key material */
   if (!silc_server_create_channel_key(server, entry,
-                                     silc_cipher_get_key_len(key) / 8)) {
+                                     silc_cipher_get_key_len(send_key) / 8)) {
     silc_idlist_del_channel(server->local_list, entry);
     return NULL;
   }
@@ -3993,16 +3348,16 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   /* Distribute to backup routers */
   if (broadcast && server->server_type == SILC_ROUTER) {
     SilcBuffer packet;
-    unsigned char *cid;
+    unsigned char cid[32];
     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);
+    SilcUInt32 id_len;
 
+    silc_id_id2str(entry->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
     packet = silc_channel_payload_encode(channel_name, name_len,
-                                        cid, channel_id_len, entry->mode);
+                                        cid, id_len, entry->mode);
     silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
-                           packet->data, packet->len, FALSE, TRUE);
-    silc_free(cid);
+                           packet->data, silc_buffer_len(packet), FALSE,
+                           TRUE);
     silc_buffer_free(packet);
   }
 
@@ -4027,7 +3382,7 @@ silc_server_create_new_channel_with_id(SilcServer server,
                                       int broadcast)
 {
   SilcChannelEntry entry;
-  SilcCipher key;
+  SilcCipher send_key, receive_key;
   SilcHmac newhmac;
 
   SILC_LOG_DEBUG(("Creating new channel %s", channel_name));
@@ -4038,12 +3393,17 @@ silc_server_create_new_channel_with_id(SilcServer server,
     hmac = SILC_DEFAULT_HMAC;
 
   /* Allocate cipher */
-  if (!silc_cipher_alloc(cipher, &key))
+  if (!silc_cipher_alloc(cipher, &send_key))
     return NULL;
+  if (!silc_cipher_alloc(cipher, &receive_key)) {
+    silc_cipher_free(send_key);
+    return NULL;
+  }
 
   /* Allocate hmac */
   if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
-    silc_cipher_free(key);
+    silc_cipher_free(send_key);
+    silc_cipher_free(receive_key);
     return NULL;
   }
 
@@ -4052,9 +3412,10 @@ silc_server_create_new_channel_with_id(SilcServer server,
   /* Create the channel */
   entry = silc_idlist_add_channel(server->local_list, channel_name,
                                  SILC_CHANNEL_MODE_NONE, channel_id,
-                                 NULL, key, newhmac, 0);
+                                 NULL, send_key, receive_key, newhmac);
   if (!entry) {
-    silc_cipher_free(key);
+    silc_cipher_free(send_key);
+    silc_cipher_free(receive_key);
     silc_hmac_free(newhmac);
     silc_free(channel_name);
     return NULL;
@@ -4062,7 +3423,7 @@ silc_server_create_new_channel_with_id(SilcServer server,
 
   /* Now create the actual key material */
   if (!silc_server_create_channel_key(server, entry,
-                                     silc_cipher_get_key_len(key) / 8)) {
+                                     silc_cipher_get_key_len(send_key) / 8)) {
     silc_idlist_del_channel(server->local_list, entry);
     return NULL;
   }
@@ -4078,16 +3439,16 @@ silc_server_create_new_channel_with_id(SilcServer server,
   /* Distribute to backup routers */
   if (broadcast && server->server_type == SILC_ROUTER) {
     SilcBuffer packet;
-    unsigned char *cid;
+    unsigned char cid[32];
     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);
+    SilcUInt32 id_len;
 
+    silc_id_id2str(entry->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
     packet = silc_channel_payload_encode(channel_name, name_len,
-                                        cid, channel_id_len, entry->mode);
+                                        cid, id_len, entry->mode);
     silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
-                           packet->data, packet->len, FALSE, TRUE);
-    silc_free(cid);
+                           packet->data, silc_buffer_len(packet), FALSE,
+                           TRUE);
     silc_buffer_free(packet);
   }
 
@@ -4124,9 +3485,9 @@ SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
    but also to re-generate new key for channel. If `key_len' is provided
    it is the bytes of the key length. */
 
-bool silc_server_create_channel_key(SilcServer server,
-                                   SilcChannelEntry channel,
-                                   SilcUInt32 key_len)
+SilcBool silc_server_create_channel_key(SilcServer server,
+                                       SilcChannelEntry channel,
+                                       SilcUInt32 key_len)
 {
   int i;
   unsigned char channel_key[32], hash[SILC_HASH_MAXLEN];
@@ -4139,9 +3500,15 @@ bool silc_server_create_channel_key(SilcServer server,
 
   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;
+  if (!channel->send_key)
+    if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->send_key)) {
+      channel->send_key = NULL;
+      return FALSE;
+    }
+  if (!channel->receive_key)
+    if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->receive_key)) {
+      silc_cipher_free(channel->send_key);
+      channel->send_key = channel->receive_key = NULL;
       return FALSE;
     }
 
@@ -4150,13 +3517,14 @@ bool silc_server_create_channel_key(SilcServer server,
   else if (channel->key_len)
     len = channel->key_len / 8;
   else
-    len = silc_cipher_get_key_len(channel->channel_key) / 8;
+    len = silc_cipher_get_key_len(channel->send_key) / 8;
 
   /* Create channel key */
   for (i = 0; i < len; i++) channel_key[i] = silc_rng_get_byte(server->rng);
 
   /* Set the key */
-  silc_cipher_set_key(channel->channel_key, channel_key, len * 8);
+  silc_cipher_set_key(channel->send_key, channel_key, len * 8, TRUE);
+  silc_cipher_set_key(channel->receive_key, channel_key, len * 8, FALSE);
 
   /* Remove old key if exists */
   if (channel->key) {
@@ -4174,7 +3542,9 @@ bool silc_server_create_channel_key(SilcServer server,
     if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
       memset(channel->key, 0, channel->key_len / 8);
       silc_free(channel->key);
-      channel->channel_key = NULL;
+      silc_cipher_free(channel->send_key);
+      silc_cipher_free(channel->receive_key);
+      channel->send_key = channel->receive_key = NULL;
       return FALSE;
     }
   silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, len, hash);
@@ -4191,12 +3561,10 @@ bool silc_server_create_channel_key(SilcServer server,
       silc_schedule_task_del(server->schedule, channel->rekey->task);
 
     channel->rekey->task =
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_channel_key_rekey,
-                            (void *)channel->rekey,
-                            server->config->channel_rekey_secs, 0,
-                            SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_channel_key_rekey,
+                                    (void *)channel->rekey,
+                                    server->config->channel_rekey_secs, 0);
   }
 
   return TRUE;
@@ -4211,14 +3579,14 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
                                              SilcChannelEntry channel)
 {
   SilcChannelKeyPayload payload = NULL;
-  SilcChannelID *id = NULL;
+  SilcChannelID id;
   unsigned char *tmp, hash[SILC_HASH_MAXLEN];
   SilcUInt32 tmp_len;
   char *cipher;
 
   /* Decode channel key payload */
   payload = silc_channel_key_payload_parse(key_payload->data,
-                                          key_payload->len);
+                                          silc_buffer_len(key_payload));
   if (!payload) {
     SILC_LOG_ERROR(("Bad channel key payload received, dropped"));
     channel = NULL;
@@ -4230,19 +3598,18 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
 
     /* Get channel ID */
     tmp = silc_channel_key_get_id(payload, &tmp_len);
-    id = silc_id_str2id(tmp, tmp_len, SILC_ID_CHANNEL);
-    if (!id) {
+    if (!silc_id_str2id(tmp, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
       channel = NULL;
       goto out;
     }
 
-    channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+    channel = silc_idlist_find_channel_by_id(server->local_list, &id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+      channel = silc_idlist_find_channel_by_id(server->global_list, &id, NULL);
       if (!channel) {
        if (server->server_type == SILC_ROUTER)
          SILC_LOG_ERROR(("Received key for non-existent channel %s",
-                         silc_id_render(id, SILC_ID_CHANNEL)));
+                         silc_id_render(&id, SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -4266,12 +3633,19 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   if (channel->key) {
     memset(channel->key, 0, channel->key_len / 8);
     silc_free(channel->key);
-    silc_cipher_free(channel->channel_key);
+    silc_cipher_free(channel->send_key);
+    silc_cipher_free(channel->receive_key);
   }
 
   /* Create new cipher */
-  if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
-    channel->channel_key = NULL;
+  if (!silc_cipher_alloc(cipher, &channel->send_key)) {
+    channel->send_key = NULL;
+    channel = NULL;
+    goto out;
+  }
+  if (!silc_cipher_alloc(cipher, &channel->receive_key)) {
+    silc_cipher_free(channel->send_key);
+    channel->send_key = channel->receive_key = NULL;
     channel = NULL;
     goto out;
   }
@@ -4283,14 +3657,17 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   /* Save the key */
   channel->key_len = tmp_len * 8;
   channel->key = silc_memdup(tmp, tmp_len);
-  silc_cipher_set_key(channel->channel_key, tmp, channel->key_len);
+  silc_cipher_set_key(channel->send_key, tmp, channel->key_len, TRUE);
+  silc_cipher_set_key(channel->receive_key, tmp, channel->key_len, FALSE);
 
   /* Generate HMAC key from the channel key data and set it */
   if (!channel->hmac)
     if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
       memset(channel->key, 0, channel->key_len / 8);
       silc_free(channel->key);
-      channel->channel_key = NULL;
+      silc_cipher_free(channel->send_key);
+      silc_cipher_free(channel->receive_key);
+      channel->send_key = channel->receive_key = NULL;
       return FALSE;
     }
   silc_hash_make(silc_hmac_get_hash(channel->hmac), tmp, tmp_len, hash);
@@ -4308,38 +3685,19 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
       silc_schedule_task_del(server->schedule, channel->rekey->task);
 
     channel->rekey->task =
-      silc_schedule_task_add(server->schedule, 0,
-                            silc_server_channel_key_rekey,
-                            (void *)channel->rekey,
-                            server->config->channel_rekey_secs, 0,
-                            SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_channel_key_rekey,
+                                    (void *)channel->rekey,
+                                    server->config->channel_rekey_secs, 0);
   }
 
  out:
-  silc_free(id);
   if (payload)
     silc_channel_key_payload_free(payload);
 
   return channel;
 }
 
-/* Heartbeat callback. This function is set as argument for the
-   silc_socket_set_heartbeat function. The library will call this function
-   at the set time interval. */
-
-void silc_server_perform_heartbeat(SilcSocketConnection sock,
-                                  void *hb_context)
-{
-  SilcServer server = hb_context;
-
-  SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname,
-                sock->port, sock->ip));
-
-  /* Send the heartbeat */
-  silc_server_send_heartbeat(server, sock);
-}
-
 /* Returns assembled of all servers in the given ID list. The packet's
    form is dictated by the New ID payload. */
 
@@ -4349,44 +3707,36 @@ static void silc_server_announce_get_servers(SilcServer server,
                                             SilcBuffer *servers,
                                             unsigned long creation_time)
 {
-  SilcIDCacheList list;
+  SilcList list;
   SilcIDCacheEntry id_cache;
   SilcServerEntry entry;
   SilcBuffer idp;
 
   /* Go through all clients in the list */
   if (silc_idcache_get_all(id_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       entry = (SilcServerEntry)id_cache->context;
-
-       /* Do not announce the one we've sending our announcements and
-          do not announce ourself. Also check the creation time if it's
-          provided. */
-       if ((entry == remote) || (entry == server->id_entry) ||
-           (creation_time && entry->data.created < creation_time)) {
-         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,
-                                      (*servers ?
-                                       (*servers)->truelen + idp->len :
-                                       idp->len));
-       silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
-       silc_buffer_put(*servers, idp->data, idp->len);
-       silc_buffer_pull(*servers, idp->len);
-       silc_buffer_free(idp);
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      entry = (SilcServerEntry)id_cache->context;
+
+      /* Do not announce the one we've sending our announcements and
+        do not announce ourself. Also check the creation time if it's
+        provided. */
+      if ((entry == remote) || (entry == server->id_entry) ||
+         (creation_time && entry->data.created < creation_time))
+       continue;
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
-      }
+      idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+
+      *servers = silc_buffer_realloc(*servers,
+                                    (*servers ?
+                                     silc_buffer_truelen((*servers)) +
+                                     silc_buffer_len(idp) :
+                                     silc_buffer_len(idp)));
+      silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
+      silc_buffer_put(*servers, idp->data, silc_buffer_len(idp));
+      silc_buffer_pull(*servers, silc_buffer_len(idp));
+      silc_buffer_free(idp);
     }
-
-    silc_idcache_list_free(list);
   }
 }
 
@@ -4408,33 +3758,33 @@ silc_server_announce_encode_notify(SilcNotifyType notify, SilcUInt32 argc, ...)
    then only the servers that has been created after the `creation_time'
    will be announced. */
 
-void silc_server_announce_servers(SilcServer server, bool global,
+void silc_server_announce_servers(SilcServer server, SilcBool global,
                                  unsigned long creation_time,
-                                 SilcSocketConnection remote)
+                                 SilcPacketStream remote)
 {
   SilcBuffer servers = NULL;
 
   SILC_LOG_DEBUG(("Announcing servers"));
 
   /* Get servers in local list */
-  silc_server_announce_get_servers(server, remote->user_data,
+  silc_server_announce_get_servers(server, silc_packet_get_context(remote),
                                   server->local_list, &servers,
                                   creation_time);
 
   if (global)
     /* Get servers in global list */
-    silc_server_announce_get_servers(server, remote->user_data,
+    silc_server_announce_get_servers(server, silc_packet_get_context(remote),
                                     server->global_list, &servers,
                                     creation_time);
 
   if (servers) {
     silc_buffer_push(servers, servers->data - servers->head);
-    SILC_LOG_HEXDUMP(("servers"), servers->data, servers->len);
+    SILC_LOG_HEXDUMP(("servers"), servers->data, silc_buffer_len(servers));
 
     /* Send the packet */
     silc_server_packet_send(server, remote,
                            SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
-                           servers->data, servers->len, TRUE);
+                           servers->data, silc_buffer_len(servers));
 
     silc_buffer_free(servers);
   }
@@ -4449,7 +3799,7 @@ static void silc_server_announce_get_clients(SilcServer server,
                                             SilcBuffer *umodes,
                                             unsigned long creation_time)
 {
-  SilcIDCacheList list;
+  SilcList list;
   SilcIDCacheEntry id_cache;
   SilcClientEntry client;
   SilcBuffer idp;
@@ -4458,58 +3808,45 @@ static void silc_server_announce_get_clients(SilcServer server,
 
   /* Go through all clients in the list */
   if (silc_idcache_get_all(id_list->clients, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       client = (SilcClientEntry)id_cache->context;
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      client = (SilcClientEntry)id_cache->context;
 
-       if (creation_time && client->data.created < creation_time) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         continue;
-       }
-       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         continue;
-       }
-       if (!client->connection && !client->router) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         continue;
-       }
+      if (creation_time && client->data.created < creation_time)
+       continue;
+      if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
+       continue;
+      if (!client->connection && !client->router)
+       continue;
 
-       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
-       *clients = silc_buffer_realloc(*clients,
-                                      (*clients ?
-                                       (*clients)->truelen + idp->len :
-                                       idp->len));
-       silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
-       silc_buffer_put(*clients, idp->data, idp->len);
-       silc_buffer_pull(*clients, idp->len);
-
-       SILC_PUT32_MSB(client->mode, mode);
-       tmp =
-         silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
-                                            2, idp->data, idp->len,
-                                            mode, 4);
-       *umodes = silc_buffer_realloc(*umodes,
-                                     (*umodes ?
-                                      (*umodes)->truelen + tmp->len :
-                                      tmp->len));
-       silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
-       silc_buffer_put(*umodes, tmp->data, tmp->len);
-       silc_buffer_pull(*umodes, tmp->len);
-       silc_buffer_free(tmp);
-
-       silc_buffer_free(idp);
-
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
-      }
+      idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+      *clients = silc_buffer_realloc(*clients,
+                                    (*clients ?
+                                     silc_buffer_truelen((*clients)) +
+                                     silc_buffer_len(idp) :
+                                     silc_buffer_len(idp)));
+      silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
+      silc_buffer_put(*clients, idp->data, silc_buffer_len(idp));
+      silc_buffer_pull(*clients, silc_buffer_len(idp));
+
+      SILC_PUT32_MSB(client->mode, mode);
+      tmp =
+       silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+                                          2, idp->data, silc_buffer_len(idp),
+                                          mode, 4);
+      *umodes = silc_buffer_realloc(*umodes,
+                                   (*umodes ?
+                                    silc_buffer_truelen((*umodes)) +
+                                    silc_buffer_len(tmp) :
+                                    silc_buffer_len(tmp)));
+      silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
+      silc_buffer_put(*umodes, tmp->data, silc_buffer_len(tmp));
+      silc_buffer_pull(*umodes, silc_buffer_len(tmp));
+      silc_buffer_free(tmp);
+
+      silc_buffer_free(idp);
     }
-
-    silc_idcache_list_free(list);
   }
 }
 
@@ -4520,7 +3857,7 @@ static void silc_server_announce_get_clients(SilcServer server,
 
 void silc_server_announce_clients(SilcServer server,
                                  unsigned long creation_time,
-                                 SilcSocketConnection remote)
+                                 SilcPacketStream remote)
 {
   SilcBuffer clients = NULL;
   SilcBuffer umodes = NULL;
@@ -4538,24 +3875,24 @@ void silc_server_announce_clients(SilcServer server,
 
   if (clients) {
     silc_buffer_push(clients, clients->data - clients->head);
-    SILC_LOG_HEXDUMP(("clients"), clients->data, clients->len);
+    SILC_LOG_HEXDUMP(("clients"), clients->data, silc_buffer_len(clients));
 
     /* Send the packet */
     silc_server_packet_send(server, remote,
                            SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
-                           clients->data, clients->len, TRUE);
+                           clients->data, silc_buffer_len(clients));
 
     silc_buffer_free(clients);
   }
 
   if (umodes) {
     silc_buffer_push(umodes, umodes->data - umodes->head);
-    SILC_LOG_HEXDUMP(("umodes"), umodes->data, umodes->len);
+    SILC_LOG_HEXDUMP(("umodes"), umodes->data, silc_buffer_len(umodes));
 
     /* Send the packet */
     silc_server_packet_send(server, remote,
                            SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                           umodes->data, umodes->len, TRUE);
+                           umodes->data, silc_buffer_len(umodes));
 
     silc_buffer_free(umodes);
   }
@@ -4572,7 +3909,8 @@ void silc_server_announce_get_channel_topic(SilcServer server,
   if (channel->topic) {
     chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
     *topic = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_TOPIC_SET, 2,
-                                               chidp->data, chidp->len,
+                                               chidp->data,
+                                               silc_buffer_len(chidp),
                                                channel->topic,
                                                strlen(channel->topic));
     silc_buffer_free(chidp);
@@ -4600,19 +3938,19 @@ void silc_server_announce_get_inviteban(SilcServer server,
     SILC_PUT16_MSB(type, list->data);
     silc_hash_table_list(channel->invite_list, &htl);
     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
-      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+      list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
                                               type);
     silc_hash_table_list_reset(&htl);
 
     idp2 = silc_id_payload_encode(server->id, SILC_ID_SERVER);
     *invite =
       silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_INVITE, 5,
-                                        idp->data, idp->len,
+                                        idp->data, silc_buffer_len(idp),
                                         channel->channel_name,
                                         strlen(channel->channel_name),
-                                        idp2->data, idp2->len,
+                                        idp2->data, silc_buffer_len(idp2),
                                         a, 1,
-                                        list->data, list->len);
+                                        list->data, silc_buffer_len(list));
     silc_buffer_free(idp2);
     silc_buffer_free(list);
   }
@@ -4624,15 +3962,15 @@ void silc_server_announce_get_inviteban(SilcServer server,
     SILC_PUT16_MSB(type, list->data);
     silc_hash_table_list(channel->ban_list, &htl);
     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
-      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+      list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
                                               type);
     silc_hash_table_list_reset(&htl);
 
     *ban =
       silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_BAN, 3,
-                                        idp->data, idp->len,
+                                        idp->data, silc_buffer_len(idp),
                                         a, 1,
-                                        list->data, list->len);
+                                        list->data, silc_buffer_len(list));
     silc_buffer_free(list);
   }
 
@@ -4667,10 +4005,11 @@ void silc_server_announce_get_channel_users(SilcServer server,
     SILC_PUT32_MSB(channel->user_limit, ulimit);
   hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL;
   if (channel->founder_key)
-    fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+    fkey = silc_public_key_payload_encode(channel->founder_key);
   tmp =
     silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                                      8, csidp->data, csidp->len,
+                                      8, csidp->data,
+                                      silc_buffer_len(csidp),
                                       mode, sizeof(mode),
                                       NULL, 0,
                                       hmac, hmac ? strlen(hmac) : 0,
@@ -4678,24 +4017,25 @@ void silc_server_announce_get_channel_users(SilcServer server,
                                       channel->passphrase ?
                                       strlen(channel->passphrase) : 0,
                                       fkey ? fkey->data : NULL,
-                                      fkey ? fkey->len : 0,
+                                      fkey ? silc_buffer_len(fkey) : 0,
                                       chpklist ? chpklist->data : NULL,
-                                      chpklist ? chpklist->len : 0,
+                                      chpklist ?
+                                      silc_buffer_len(chpklist) : 0,
                                       (channel->mode &
                                        SILC_CHANNEL_MODE_ULIMIT ?
                                        ulimit : NULL),
                                       (channel->mode &
                                        SILC_CHANNEL_MODE_ULIMIT ?
                                        sizeof(ulimit) : 0));
-  len = tmp->len;
+  len = silc_buffer_len(tmp);
   *channel_modes =
     silc_buffer_realloc(*channel_modes,
                        (*channel_modes ?
-                        (*channel_modes)->truelen + len : len));
+                        silc_buffer_truelen((*channel_modes)) + len : len));
   silc_buffer_pull_tail(*channel_modes,
                        ((*channel_modes)->end -
                         (*channel_modes)->data));
-  silc_buffer_put(*channel_modes, tmp->data, tmp->len);
+  silc_buffer_put(*channel_modes, tmp->data, silc_buffer_len(tmp));
   silc_buffer_pull(*channel_modes, len);
   silc_buffer_free(tmp);
   silc_buffer_free(fkey);
@@ -4708,41 +4048,46 @@ void silc_server_announce_get_channel_users(SilcServer server,
 
     /* JOIN Notify */
     tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_JOIN, 2,
-                                            clidp->data, clidp->len,
-                                            chidp->data, chidp->len);
-    len = tmp->len;
+                                            clidp->data,
+                                            silc_buffer_len(clidp),
+                                            chidp->data,
+                                            silc_buffer_len(chidp));
+    len = silc_buffer_len(tmp);
     *channel_users =
       silc_buffer_realloc(*channel_users,
                          (*channel_users ?
-                          (*channel_users)->truelen + len : len));
+                          silc_buffer_truelen((*channel_users)) + len : len));
     silc_buffer_pull_tail(*channel_users,
                          ((*channel_users)->end -
                           (*channel_users)->data));
 
-    silc_buffer_put(*channel_users, tmp->data, tmp->len);
+    silc_buffer_put(*channel_users, tmp->data, silc_buffer_len(tmp));
     silc_buffer_pull(*channel_users, len);
     silc_buffer_free(tmp);
 
     /* CUMODE notify for mode change on the channel */
     SILC_PUT32_MSB(chl->mode, mode);
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && channel->founder_key)
-      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+      fkey = silc_public_key_payload_encode(channel->founder_key);
     tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
-                                            4, csidp->data, csidp->len,
+                                            4, csidp->data,
+                                            silc_buffer_len(csidp),
                                             mode, sizeof(mode),
-                                            clidp->data, clidp->len,
+                                            clidp->data,
+                                            silc_buffer_len(clidp),
                                             fkey ? fkey->data : NULL,
-                                            fkey ? fkey->len : 0);
-    len = tmp->len;
+                                            fkey ? silc_buffer_len(fkey) : 0);
+    len = silc_buffer_len(tmp);
     *channel_users_modes =
       silc_buffer_realloc(*channel_users_modes,
                          (*channel_users_modes ?
-                          (*channel_users_modes)->truelen + len : len));
+                          silc_buffer_truelen((*channel_users_modes)) +
+                          len : len));
     silc_buffer_pull_tail(*channel_users_modes,
                          ((*channel_users_modes)->end -
                           (*channel_users_modes)->data));
 
-    silc_buffer_put(*channel_users_modes, tmp->data, tmp->len);
+    silc_buffer_put(*channel_users_modes, tmp->data, silc_buffer_len(tmp));
     silc_buffer_pull(*channel_users_modes, len);
     silc_buffer_free(tmp);
     silc_buffer_free(fkey);
@@ -4771,105 +4116,98 @@ void silc_server_announce_get_channels(SilcServer server,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time)
 {
-  SilcIDCacheList list;
+  SilcList list;
   SilcIDCacheEntry id_cache;
   SilcChannelEntry channel;
-  unsigned char *cid;
+  unsigned char cid[32];
   SilcUInt32 id_len;
   SilcUInt16 name_len;
   int len;
   int i = *channel_users_modes_c;
-  bool announce;
+  SilcBool announce;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Go through all channels in the list */
   if (silc_idcache_get_all(id_list->channels, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       channel = (SilcChannelEntry)id_cache->context;
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      channel = (SilcChannelEntry)id_cache->context;
 
-       if (creation_time && channel->created < creation_time)
-         announce = FALSE;
-       else
-         announce = TRUE;
-
-       cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
-       name_len = strlen(channel->channel_name);
-
-       if (announce) {
-         len = 4 + name_len + id_len + 4;
-         *channels =
-           silc_buffer_realloc(*channels,
-                               (*channels ? (*channels)->truelen +
-                                len : len));
-         silc_buffer_pull_tail(*channels,
-                               ((*channels)->end - (*channels)->data));
-         silc_buffer_format(*channels,
-                            SILC_STR_UI_SHORT(name_len),
-                            SILC_STR_UI_XNSTRING(channel->channel_name,
-                                                 name_len),
-                            SILC_STR_UI_SHORT(id_len),
+      if (creation_time && channel->created < creation_time)
+       announce = FALSE;
+      else
+       announce = TRUE;
+
+      silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
+      name_len = strlen(channel->channel_name);
+
+      if (announce) {
+       len = 4 + name_len + id_len + 4;
+       *channels =
+         silc_buffer_realloc(*channels,
+                             (*channels ?
+                              silc_buffer_truelen((*channels)) +
+                              len : len));
+       silc_buffer_pull_tail(*channels,
+                             ((*channels)->end - (*channels)->data));
+       silc_buffer_format(*channels,
+                          SILC_STR_UI_SHORT(name_len),
+                          SILC_STR_UI_XNSTRING(channel->channel_name,
+                                               name_len),
+                          SILC_STR_UI_SHORT(id_len),
                             SILC_STR_UI_XNSTRING(cid, id_len),
-                            SILC_STR_UI_INT(channel->mode),
-                            SILC_STR_END);
-         silc_buffer_pull(*channels, len);
-       }
+                          SILC_STR_UI_INT(channel->mode),
+                          SILC_STR_END);
+       silc_buffer_pull(*channels, len);
+      }
 
-       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,
+      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's invite and ban list */
-         *channel_invites = silc_realloc(*channel_invites,
-                                         sizeof(**channel_invites) * (i + 1));
-         (*channel_invites)[i] = NULL;
-         *channel_bans = silc_realloc(*channel_bans,
-                                      sizeof(**channel_bans) * (i + 1));
-         (*channel_bans)[i] = NULL;
-         silc_server_announce_get_inviteban(server, channel,
-                                            &(*channel_invites)[i],
-                                            &(*channel_bans)[i]);
-
-         (*channel_users_modes_c)++;
-         silc_free(cid);
-
-         i++;
-       }
-
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+       (*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's invite and ban list */
+       *channel_invites = silc_realloc(*channel_invites,
+                                       sizeof(**channel_invites) * (i + 1));
+       (*channel_invites)[i] = NULL;
+       *channel_bans = silc_realloc(*channel_bans,
+                                    sizeof(**channel_bans) * (i + 1));
+       (*channel_bans)[i] = NULL;
+       silc_server_announce_get_inviteban(server, channel,
+                                          &(*channel_invites)[i],
+                                          &(*channel_bans)[i]);
+
+       (*channel_users_modes_c)++;
+
+       i++;
       }
     }
-
-    silc_idcache_list_free(list);
   }
 }
 
@@ -4882,7 +4220,7 @@ void silc_server_announce_get_channels(SilcServer server,
 
 void silc_server_announce_channels(SilcServer server,
                                   unsigned long creation_time,
-                                  SilcSocketConnection remote)
+                                  SilcPacketStream remote)
 {
   SilcBuffer channels = NULL, *channel_modes = NULL, channel_users = NULL;
   SilcBuffer *channel_users_modes = NULL;
@@ -4919,13 +4257,12 @@ void silc_server_announce_channels(SilcServer server,
 
   if (channels) {
     silc_buffer_push(channels, channels->data - channels->head);
-    SILC_LOG_HEXDUMP(("channels"), channels->data, channels->len);
+    SILC_LOG_HEXDUMP(("channels"), channels->data, silc_buffer_len(channels));
 
     /* Send the packet */
     silc_server_packet_send(server, remote,
                            SILC_PACKET_NEW_CHANNEL, SILC_PACKET_FLAG_LIST,
-                           channels->data, channels->len,
-                           FALSE);
+                           channels->data, silc_buffer_len(channels));
 
     silc_buffer_free(channels);
   }
@@ -4933,13 +4270,12 @@ void silc_server_announce_channels(SilcServer server,
   if (channel_users) {
     silc_buffer_push(channel_users, channel_users->data - channel_users->head);
     SILC_LOG_HEXDUMP(("channel users"), channel_users->data,
-                    channel_users->len);
+                    silc_buffer_len(channel_users));
 
     /* Send the packet */
     silc_server_packet_send(server, remote,
                            SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                           channel_users->data, channel_users->len,
-                           FALSE);
+                           channel_users->data, silc_buffer_len(channel_users));
 
     silc_buffer_free(channel_users);
   }
@@ -4954,13 +4290,12 @@ void silc_server_announce_channels(SilcServer server,
                       channel_modes[i]->data -
                       channel_modes[i]->head);
       SILC_LOG_HEXDUMP(("channel modes"), channel_modes[i]->data,
-                      channel_modes[i]->len);
+                      silc_buffer_len(channel_modes[i]));
       silc_server_packet_send_dest(server, remote,
                                   SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                   channel_ids[i], SILC_ID_CHANNEL,
                                   channel_modes[i]->data,
-                                  channel_modes[i]->len,
-                                  FALSE);
+                                  silc_buffer_len(channel_modes[i]));
       silc_buffer_free(channel_modes[i]);
     }
     silc_free(channel_modes);
@@ -4976,13 +4311,12 @@ void silc_server_announce_channels(SilcServer server,
                       channel_users_modes[i]->data -
                       channel_users_modes[i]->head);
       SILC_LOG_HEXDUMP(("channel users modes"), channel_users_modes[i]->data,
-                      channel_users_modes[i]->len);
+                      silc_buffer_len(channel_users_modes[i]));
       silc_server_packet_send_dest(server, remote,
                                   SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                   channel_ids[i], SILC_ID_CHANNEL,
                                   channel_users_modes[i]->data,
-                                  channel_users_modes[i]->len,
-                                  FALSE);
+                                  silc_buffer_len(channel_users_modes[i]));
       silc_buffer_free(channel_users_modes[i]);
     }
     silc_free(channel_users_modes);
@@ -4999,13 +4333,12 @@ void silc_server_announce_channels(SilcServer server,
                       channel_topics[i]->data -
                       channel_topics[i]->head);
       SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data,
-                      channel_topics[i]->len);
+                      silc_buffer_len(channel_topics[i]));
       silc_server_packet_send_dest(server, remote,
                                   SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                   channel_ids[i], SILC_ID_CHANNEL,
                                   channel_topics[i]->data,
-                                  channel_topics[i]->len,
-                                  FALSE);
+                                  silc_buffer_len(channel_topics[i]));
       silc_buffer_free(channel_topics[i]);
     }
     silc_free(channel_topics);
@@ -5022,13 +4355,12 @@ void silc_server_announce_channels(SilcServer server,
                       channel_invites[i]->data -
                       channel_invites[i]->head);
       SILC_LOG_HEXDUMP(("channel invite list"), channel_invites[i]->data,
-                      channel_invites[i]->len);
+                      silc_buffer_len(channel_invites[i]));
       silc_server_packet_send_dest(server, remote,
                                   SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                   channel_ids[i], SILC_ID_CHANNEL,
                                   channel_invites[i]->data,
-                                  channel_invites[i]->len,
-                                  FALSE);
+                                  silc_buffer_len(channel_invites[i]));
       silc_buffer_free(channel_invites[i]);
     }
     silc_free(channel_invites);
@@ -5045,13 +4377,12 @@ void silc_server_announce_channels(SilcServer server,
                       channel_bans[i]->data -
                       channel_bans[i]->head);
       SILC_LOG_HEXDUMP(("channel ban list"), channel_bans[i]->data,
-                      channel_bans[i]->len);
+                      silc_buffer_len(channel_bans[i]));
       silc_server_packet_send_dest(server, remote,
                                   SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                   channel_ids[i], SILC_ID_CHANNEL,
                                   channel_bans[i]->data,
-                                  channel_bans[i]->len,
-                                  FALSE);
+                                  silc_buffer_len(channel_bans[i]));
       silc_buffer_free(channel_bans[i]);
     }
     silc_free(channel_bans);
@@ -5063,7 +4394,7 @@ void silc_server_announce_channels(SilcServer server,
 /* Announces WATCH list. */
 
 void silc_server_announce_watches(SilcServer server,
-                                 SilcSocketConnection remote)
+                                 SilcPacketStream remote)
 {
   SilcHashTableList htl;
   SilcBuffer buffer, idp, args, pkp;
@@ -5088,16 +4419,18 @@ void silc_server_announce_watches(SilcServer server,
     silc_buffer_format(args,
                       SILC_STR_UI_SHORT(1),
                       SILC_STR_END);
-    pkp = silc_pkcs_public_key_payload_encode(key);
-    args = silc_argument_payload_encode_one(args, pkp->data, pkp->len, 0x00);
+    pkp = silc_public_key_payload_encode(key);
+    args = silc_argument_payload_encode_one(args, pkp->data,
+                                           silc_buffer_len(pkp), 0x00);
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
                                            ++server->cmd_ident, 2,
-                                           1, idp->data, idp->len,
-                                           4, args->data, args->len);
+                                           1, idp->data, silc_buffer_len(idp),
+                                           4, args->data,
+                                           silc_buffer_len(args));
 
     /* Send command */
     silc_server_packet_send(server, remote, SILC_PACKET_COMMAND, 0,
-                           buffer->data, buffer->len, TRUE);
+                           buffer->data, silc_buffer_len(buffer));
 
     silc_buffer_free(pkp);
     silc_buffer_free(args);
@@ -5109,7 +4442,7 @@ void silc_server_announce_watches(SilcServer server,
 
 /* Assembles user list and users mode list from the `channel'. */
 
-bool silc_server_get_users_on_channel(SilcServer server,
+SilcBool silc_server_get_users_on_channel(SilcServer server,
                                      SilcChannelEntry channel,
                                      SilcBuffer *user_list,
                                      SilcBuffer *mode_list,
@@ -5133,15 +4466,16 @@ bool silc_server_get_users_on_channel(SilcServer server,
   client_id_list = silc_buffer_alloc(len);
   client_mode_list =
     silc_buffer_alloc(4 * silc_hash_table_count(channel->user_list));
-  silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
-  silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
+  silc_buffer_pull_tail(client_id_list, silc_buffer_truelen(client_id_list));
+  silc_buffer_pull_tail(client_mode_list,
+                       silc_buffer_truelen(client_mode_list));
 
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
     /* Client ID */
     idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
-    silc_buffer_put(client_id_list, idp->data, idp->len);
-    silc_buffer_pull(client_id_list, idp->len);
+    silc_buffer_put(client_id_list, idp->data, silc_buffer_len(idp));
+    silc_buffer_pull(client_id_list, silc_buffer_len(idp));
     silc_buffer_free(idp);
 
     /* Client's mode on channel */
@@ -5165,7 +4499,7 @@ bool silc_server_get_users_on_channel(SilcServer server,
 /* Saves users and their modes to the `channel'. */
 
 void silc_server_save_users_on_channel(SilcServer server,
-                                      SilcSocketConnection sock,
+                                      SilcPacketStream sock,
                                       SilcChannelEntry channel,
                                       SilcClientID *noadd,
                                       SilcBuffer user_list,
@@ -5175,7 +4509,7 @@ void silc_server_save_users_on_channel(SilcServer server,
   int i;
   SilcUInt16 idp_len;
   SilcUInt32 mode;
-  SilcClientID *client_id;
+  SilcID id;
   SilcClientEntry client;
   SilcIDCacheEntry cache;
   SilcChannelClientEntry chl;
@@ -5187,56 +4521,49 @@ void silc_server_save_users_on_channel(SilcServer server,
     /* Client ID */
     SILC_GET16_MSB(idp_len, user_list->data + 2);
     idp_len += 4;
-    client_id = silc_id_payload_parse_id(user_list->data, idp_len, NULL);
-    silc_buffer_pull(user_list, idp_len);
-    if (!client_id)
+    if (!silc_id_payload_parse_id(user_list->data, idp_len, &id))
       continue;
+    silc_buffer_pull(user_list, idp_len);
 
     /* Mode */
     SILC_GET32_MSB(mode, mode_list->data);
     silc_buffer_pull(mode_list, 4);
 
-    if (noadd && SILC_ID_CLIENT_COMPARE(client_id, noadd)) {
-      silc_free(client_id);
+    if (noadd && SILC_ID_CLIENT_COMPARE(&id.u.client_id, noadd))
       continue;
-    }
 
     cache = NULL;
 
     /* Check if we have this client cached already. */
-    client = silc_idlist_find_client_by_id(server->local_list, client_id,
+    client = silc_idlist_find_client_by_id(server->local_list,
+                                          &id.u.client_id,
                                           server->server_type, &cache);
     if (!client)
       client = silc_idlist_find_client_by_id(server->global_list,
-                                            client_id, server->server_type,
-                                            &cache);
+                                            &id.u.client_id,
+                                            server->server_type, &cache);
     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_SERVER) {
-       silc_free(client_id);
+      if (server->server_type != SILC_SERVER)
        continue;
-      }
 
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be
         global. */
       client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
-                                     silc_id_dup(client_id, SILC_ID_CLIENT),
-                                     sock->user_data, NULL, 0);
+                                     silc_id_dup(&id.u.client_id,
+                                                 SILC_ID_CLIENT),
+                                     silc_packet_get_context(sock),
+                                     NULL);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
-       silc_free(client_id);
        continue;
       }
 
       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     }
 
-    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));
@@ -5264,7 +4591,7 @@ void silc_server_save_users_on_channel(SilcServer server,
    it has joined. */
 
 void silc_server_save_user_channels(SilcServer server,
-                                   SilcSocketConnection sock,
+                                   SilcPacketStream sock,
                                    SilcClientEntry client,
                                    SilcBuffer channels,
                                    SilcBuffer channels_user_modes)
@@ -5273,7 +4600,7 @@ void silc_server_save_user_channels(SilcServer server,
   SilcUInt32 *chumodes;
   SilcChannelPayload entry;
   SilcChannelEntry channel;
-  SilcChannelID *channel_id;
+  SilcChannelID channel_id;
   SilcChannelClientEntry chl;
   SilcHashTable ht = NULL;
   SilcHashTableList htl;
@@ -5284,7 +4611,8 @@ void silc_server_save_user_channels(SilcServer server,
       !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
     goto out;
 
-  ch = silc_channel_payload_parse_list(channels->data, channels->len);
+  ch = silc_channel_payload_parse_list(channels->data,
+                                      silc_buffer_len(channels));
   if (ch && silc_get_mode_list(channels_user_modes, silc_dlist_count(ch),
                               &chumodes)) {
     ht = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
@@ -5293,15 +4621,15 @@ void silc_server_save_user_channels(SilcServer server,
     while ((entry = silc_dlist_get(ch)) != SILC_LIST_END) {
       /* Check if we have this channel, and add it if we don't have it.
         Also add the client on the channel unless it is there already. */
-      channel_id = silc_channel_get_id_parse(entry);
+      if (!silc_channel_get_id_parse(entry, &channel_id))
+       continue;
       channel = silc_idlist_find_channel_by_id(server->local_list,
-                                              channel_id, NULL);
+                                              &channel_id, NULL);
       if (!channel)
        channel = silc_idlist_find_channel_by_id(server->global_list,
-                                                channel_id, NULL);
+                                                &channel_id, NULL);
       if (!channel) {
        if (server->server_type != SILC_SERVER) {
-         silc_free(channel_id);
          i++;
          continue;
        }
@@ -5309,14 +4637,13 @@ void silc_server_save_user_channels(SilcServer server,
        /* We don't have that channel anywhere, add it. */
        name = silc_channel_get_name(entry, NULL);
        channel = silc_idlist_add_channel(server->global_list, strdup(name), 0,
-                                         channel_id, server->router,
-                                         NULL, NULL, 0);
+                                         silc_id_dup(&channel_id,
+                                                     SILC_ID_CHANNEL),
+                                         server->router, NULL, NULL, 0);
        if (!channel) {
-         silc_free(channel_id);
          i++;
          continue;
        }
-       channel_id = NULL;
       }
 
       channel->mode = silc_channel_get_mode(entry);
@@ -5336,7 +4663,6 @@ void silc_server_save_user_channels(SilcServer server,
       }
 
       silc_hash_table_add(ht, channel, channel);
-      silc_free(channel_id);
     }
     silc_channel_payload_list_free(ch);
     silc_free(chumodes);
@@ -5372,7 +4698,7 @@ void silc_server_save_user_channels(SilcServer server,
    could not be found to the client. If the `client_id' is specified then
    it is used and the `id_data' is ignored. */
 
-SilcSocketConnection
+SilcPacketStream
 silc_server_get_client_route(SilcServer server,
                             unsigned char *id_data,
                             SilcUInt32 id_len,
@@ -5380,7 +4706,7 @@ silc_server_get_client_route(SilcServer server,
                             SilcIDListData *idata,
                             SilcClientEntry *client_entry)
 {
-  SilcClientID *id;
+  SilcClientID *id, clid;
   SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
@@ -5390,11 +4716,9 @@ silc_server_get_client_route(SilcServer server,
 
   /* Decode destination Client ID */
   if (!client_id) {
-    id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
-    if (!id) {
-      SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+    if (!silc_id_str2id(id_data, id_len, SILC_ID_CHANNEL, &clid, sizeof(clid)))
       return NULL;
-    }
+    id = silc_id_dup(&clid, SILC_ID_CLIENT);
   } else {
     id = silc_id_dup(client_id, SILC_ID_CLIENT);
   }
@@ -5440,13 +4764,13 @@ silc_server_get_client_route(SilcServer server,
     client = silc_idlist_find_client_by_id(server->global_list, id,
                                           TRUE, NULL);
     if (client) {
-      SilcSocketConnection dst_sock;
+      SilcPacketStream dst_sock;
 
       dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
 
       silc_free(id);
       if (idata && dst_sock)
-       *idata = (SilcIDListData)dst_sock->user_data;
+       *idata = silc_packet_get_context(dst_sock);
       return dst_sock;
     }
   }
@@ -5460,15 +4784,15 @@ silc_server_get_client_route(SilcServer server,
 
 SilcBuffer silc_server_get_client_channel_list(SilcServer server,
                                               SilcClientEntry client,
-                                              bool get_private,
-                                              bool get_secret,
+                                              SilcBool get_private,
+                                              SilcBool get_secret,
                                               SilcBuffer *user_mode_list)
 {
   SilcBuffer buffer = NULL;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
-  unsigned char *cid;
+  unsigned char cid[32];
   SilcUInt32 id_len;
   SilcUInt16 name_len;
   int len;
@@ -5485,30 +4809,28 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
     if (channel->mode & SILC_CHANNEL_MODE_PRIVATE && !get_private)
       continue;
 
-    cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-    id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+    silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
     name_len = strlen(channel->channel_name);
 
     len = 4 + name_len + id_len + 4;
     buffer = silc_buffer_realloc(buffer,
-                                (buffer ? buffer->truelen + len : len));
+                                (buffer ?
+                                 silc_buffer_truelen(buffer) + len : len));
     silc_buffer_pull_tail(buffer, (buffer->end - buffer->data));
     silc_buffer_format(buffer,
                       SILC_STR_UI_SHORT(name_len),
-                      SILC_STR_UI_XNSTRING(channel->channel_name,
-                                           name_len),
+                      SILC_STR_DATA(channel->channel_name, name_len),
                       SILC_STR_UI_SHORT(id_len),
-                      SILC_STR_UI_XNSTRING(cid, id_len),
+                      SILC_STR_DATA(cid, id_len),
                       SILC_STR_UI_INT(chl->channel->mode),
                       SILC_STR_END);
     silc_buffer_pull(buffer, len);
-    silc_free(cid);
 
     if (user_mode_list) {
-      *user_mode_list = silc_buffer_realloc(*user_mode_list,
-                                           (*user_mode_list ?
-                                            (*user_mode_list)->truelen + 4 :
-                                            4));
+      *user_mode_list =
+       silc_buffer_realloc(*user_mode_list,
+                           (*user_mode_list ?
+                            silc_buffer_truelen((*user_mode_list)) + 4 : 4));
       silc_buffer_pull_tail(*user_mode_list, ((*user_mode_list)->end -
                                              (*user_mode_list)->data));
       SILC_PUT32_MSB(chl->mode, (*user_mode_list)->data);
@@ -5526,192 +4848,6 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   return buffer;
 }
 
-/* Timeout callback for unsuccessful rekey.  The rekey did not go through
-   for some reason. */
-
-SILC_TASK_CALLBACK(silc_server_rekey_timeout)
-{
-  SilcServerRekeyInternalContext *ctx = context;
-  SilcServer server = app_context;
-  SilcSocketConnection sock = ctx->sock;
-
-  SILC_LOG_DEBUG(("Timeout occurred in rekey protocol with %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")));
-
-  SILC_LOG_WARNING(("Timeout occurred in rekey protocol with %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")));
-
-  if (sock->protocol) {
-    silc_protocol_cancel(sock->protocol, server->schedule);
-    silc_protocol_free(sock->protocol);
-    sock->protocol = NULL;
-  }
-  if (ctx->packet)
-    silc_packet_context_free(ctx->packet);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
-  silc_socket_free(sock);
-  silc_free(ctx);
-
-  /* Disconnect since we failed to rekey, the keys are probably wrong. */
-  silc_server_disconnect_remote(server, sock,
-                               SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
-  if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock, NULL);
-
-  /* Reconnect */
-  if (sock->type != SILC_SOCKET_TYPE_CLIENT)
-    silc_server_create_connections(server);
-}
-
-/* A timeout callback for the re-key. We will be the initiator of the
-   re-key protocol. */
-
-SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
-{
-  SilcServer server = app_context;
-  SilcSocketConnection sock = (SilcSocketConnection)context;
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
-  SilcProtocol protocol;
-  SilcServerRekeyInternalContext *proto_ctx;
-
-  if (!idata)
-    return;
-
-  /* Do not execute rekey with disabled connections, as it would not
-     go through anyway. */
-  if (idata->status & SILC_IDLIST_STATUS_DISABLED)
-    return;
-
-  /* If rekey protocol is active already wait for it to finish */
-  if (sock->protocol && sock->protocol->protocol &&
-      sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)
-    return;
-
-  /* If any other protocol is active do not start this protocol yet. */
-  if (sock->protocol) {
-    SILC_LOG_DEBUG(("Waiting for other protocol to finish before rekeying"));
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_rekey_callback,
-                          sock, 60, 0, SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Executing rekey protocol with %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")));
-
-  /* Allocate internal protocol context. This is sent as context
-     to the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->server = (void *)server;
-  proto_ctx->sock = silc_socket_dup(sock);
-  proto_ctx->responder = FALSE;
-  proto_ctx->pfs = idata->rekey->pfs;
-
-  /* Perform rekey protocol. Will call the final callback after the
-     protocol is over. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
-                     &protocol, proto_ctx, silc_server_rekey_final);
-  sock->protocol = protocol;
-
-  /* Register timeout callback in case the rekey does not go through. */
-  proto_ctx->timeout_task =
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_rekey_timeout,
-                          proto_ctx,
-                          (idata->rekey->timeout >
-                           server->config->key_exchange_timeout ?
-                           idata->rekey->timeout :
-                           server->config->key_exchange_timeout * 4), 0,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW);
-
-  /* Run the protocol */
-  silc_protocol_execute(protocol, server->schedule, 0, 0);
-}
-
-/* The final callback for the REKEY protocol. This will actually take the
-   new key material into use. */
-
-SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerRekeyInternalContext *ctx =
-    (SilcServerRekeyInternalContext *)protocol->context;
-  SilcServer server = (SilcServer)ctx->server;
-  SilcSocketConnection sock = ctx->sock;
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
-
-  if (ctx->timeout_task)
-    silc_schedule_task_del(server->schedule, ctx->timeout_task);
-
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-    /* Error occured during protocol */
-    SILC_LOG_ERROR(("Error occurred during rekey protocol with "
-                   "%s (%s)", sock->hostname, sock->ip));
-    silc_protocol_cancel(protocol, server->schedule);
-    silc_protocol_free(protocol);
-    sock->protocol = NULL;
-    if (ctx->packet)
-      silc_packet_context_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_socket_free(sock);
-    silc_free(ctx);
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
-
-    /* Reconnect */
-    if (sock->type != SILC_SOCKET_TYPE_CLIENT)
-      silc_server_create_connections(server);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Rekey protocol completed with %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")));
-
-  /* Purge the outgoing data queue to assure that all rekey packets really
-     go to the network before we quit the protocol. */
-  silc_server_packet_queue_purge(server, sock);
-
-  /* Re-register re-key timeout */
-  if (ctx->responder == FALSE)
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_rekey_callback,
-                          sock, idata->rekey->timeout, 0,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-
-  /* Cleanup */
-  silc_protocol_free(protocol);
-  sock->protocol = NULL;
-  if (ctx->packet)
-    silc_packet_context_free(ctx->packet);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
-  silc_socket_free(sock);
-  silc_free(ctx);
-}
-
 /* Task callback used to retrieve network statistical information from
    router server once in a while. */
 
@@ -5726,15 +4862,15 @@ SILC_TASK_CALLBACK(silc_server_get_stats)
     idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
     packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
                                            ++server->cmd_ident, 1,
-                                           1, idp->data, idp->len);
+                                           1, idp->data,
+                                           silc_buffer_len(idp));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, 0, packet->data,
-                           packet->len, FALSE);
+                           silc_buffer_len(packet));
     silc_buffer_free(packet);
     silc_buffer_free(idp);
   }
 
-  silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
-                        server, 120, 0, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_LOW);
+  silc_schedule_task_add_timeout(server->schedule, silc_server_get_stats,
+                                server, 120, 0);
 }
index 07f5d63d24b468694a8046e1cfe692528404a4b5..3b3bee771ec0cfbef784d20f18d38b9ed72c79ea 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 #ifndef SERVER_H
 #define SERVER_H
 
-/* Forward declaration of backup server context */
+/* Forward declarations */
+typedef struct SilcServerEntryStruct *SilcServerEntry;
+typedef struct SilcClientEntryStruct *SilcClientEntry;
+typedef struct SilcChannelEntryStruct *SilcChannelEntry;
 typedef struct SilcServerBackupStruct *SilcServerBackup;
+typedef struct SilcIDListDataObject *SilcIDListData, SilcIDListDataStruct;
+typedef struct SilcIDListStruct *SilcIDList;
 
 /* Callback function that is called after the key exchange and connection
    authentication protocols has been completed with a remote router. The
    `server_entry' is the remote router entry or NULL on error. */
-typedef void (*SilcServerConnectRouterCallback)(SilcServer server,
-                                               SilcServerEntry server_entry,
-                                               void *context);
+typedef void (*SilcServerConnectCallback)(SilcServer server,
+                                         SilcServerEntry server_entry,
+                                         void *context);
 
 /* Connection structure used when connection to remote */
-typedef struct {
-  SilcSocketConnection sock;
+typedef struct SilcServerConnectionStruct {
+  SilcServer server;
+  SilcStream stream;
+  SilcPacketStream sock;
+  SilcAsyncOperation op;
+  SilcServerConfigRef conn;
 
-  /* Remote host name and port */
   char *remote_host;
   int remote_port;
-  bool backup;
+
   char *backup_replace_ip;
   int backup_replace_port;
-  bool no_reconnect;
-
-  /* Connection configuration (maybe NULL) */
-  SilcServerConfigRef conn;
 
   /* Current connection retry info */
   SilcUInt32 retry_count;
   SilcUInt32 retry_timeout;
-
-  SilcServerConnectRouterCallback callback;
+  SilcServerConnectCallback callback;
   void *callback_context;
+  int rekey_timeout;
+
+  unsigned int backup          : 1;   /* Set when backup router connection */
+  unsigned int backup_resuming : 1;   /* Set when running resuming protocol */
+  unsigned int no_reconnect    : 1;   /* Set when to not reconnect */
+  unsigned int no_conf         : 1;   /* Set when connecting without pre-
+                                        configuration. */
 } *SilcServerConnection;
 
 /* General definitions */
@@ -115,11 +125,6 @@ do {                                                                       \
   (sock->protocol && sock->protocol->protocol &&                       \
    sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)
 
-/* Check whether backup resuming protocol is active */
-#define SILC_SERVER_IS_BACKUP(sock)                                    \
-  (sock->protocol && sock->protocol->protocol &&                       \
-   sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP)
-
 /* Output a message to stderr or to the appropriate log facility wether
    we are in the background or not. */
 #define SILC_SERVER_LOG_INFO(fmt)                                      \
@@ -132,45 +137,41 @@ do {                                                                      \
   silc_server_stderr(SILC_LOG_WARNING, silc_format fmt)
 
 /* Prototypes */
-int silc_server_alloc(SilcServer *new_server);
+SilcBool silc_server_alloc(SilcServer *new_server);
 void silc_server_free(SilcServer server);
-bool silc_server_init(SilcServer server);
-bool silc_server_rehash(SilcServer server);
+SilcBool silc_server_init(SilcServer server);
+SilcBool silc_server_rehash(SilcServer server);
 void silc_server_run(SilcServer server);
 void silc_server_stop(SilcServer server);
-void silc_server_start_key_exchange(SilcServer server,
-                                   SilcServerConnection sconn,
-                                   int sock);
-bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
-                             void *context);
-void silc_server_packet_parse_type(SilcServer server,
-                                  SilcSocketConnection sock,
-                                  SilcPacketContext *packet);
+void silc_server_start_key_exchange(SilcServerConnection sconn);
 void silc_server_create_connection(SilcServer server,
-                                  const char *remote_host, SilcUInt32 port);
+                                  SilcBool reconnect,
+                                  const char *remote_host, SilcUInt32 port,
+                                  SilcServerConnectCallback callback,
+                                  void *context);
 void silc_server_close_connection(SilcServer server,
-                                 SilcSocketConnection sock);
+                                 SilcPacketStream sock);
 void silc_server_free_client_data(SilcServer server,
-                                 SilcSocketConnection sock,
+                                 SilcPacketStream sock,
                                  SilcClientEntry client,
                                  int notify,
                                  const char *signoff);
 void silc_server_free_sock_user_data(SilcServer server,
-                                    SilcSocketConnection sock,
+                                    SilcPacketStream sock,
                                     const char *signoff_message);
 void silc_server_remove_from_channels(SilcServer server,
-                                     SilcSocketConnection sock,
+                                     SilcPacketStream sock,
                                      SilcClientEntry client,
-                                     bool notify,
+                                     SilcBool notify,
                                      const char *signoff_message,
-                                     bool keygen, bool killed);
-bool silc_server_remove_from_one_channel(SilcServer server,
-                                        SilcSocketConnection sock,
+                                     SilcBool keygen, bool killed);
+SilcBool silc_server_remove_from_one_channel(SilcServer server,
+                                        SilcPacketStream sock,
                                         SilcChannelEntry channel,
                                         SilcClientEntry client,
-                                        bool notify);
+                                        SilcBool notify);
 void silc_server_disconnect_remote(SilcServer server,
-                                  SilcSocketConnection sock,
+                                  SilcPacketStream sock,
                                   SilcStatus status, ...);
 SilcChannelEntry silc_server_create_new_channel(SilcServer server,
                                                SilcServerID *router_id,
@@ -185,13 +186,13 @@ silc_server_create_new_channel_with_id(SilcServer server,
                                       char *channel_name,
                                       SilcChannelID *channel_id,
                                       int broadcast);
-bool silc_server_create_channel_key(SilcServer server,
+SilcBool silc_server_create_channel_key(SilcServer server,
                                    SilcChannelEntry channel,
                                    SilcUInt32 key_len);
 SilcChannelEntry silc_server_save_channel_key(SilcServer server,
                                              SilcBuffer key_payload,
                                              SilcChannelEntry channel);
-void silc_server_perform_heartbeat(SilcSocketConnection sock,
+void silc_server_perform_heartbeat(SilcPacketStream sock,
                                   void *hb_context);
 void silc_server_announce_get_channel_topic(SilcServer server,
                                            SilcChannelEntry channel,
@@ -213,35 +214,35 @@ void silc_server_announce_get_channels(SilcServer server,
                                       SilcBuffer **channel_bans,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time);
-void silc_server_announce_servers(SilcServer server, bool global,
+void silc_server_announce_servers(SilcServer server, SilcBool global,
                                  unsigned long creation_time,
-                                 SilcSocketConnection remote);
+                                 SilcPacketStream remote);
 void silc_server_announce_clients(SilcServer server,
                                  unsigned long creation_time,
-                                 SilcSocketConnection remote);
+                                 SilcPacketStream remote);
 void silc_server_announce_channels(SilcServer server,
                                   unsigned long creation_time,
-                                  SilcSocketConnection remote);
+                                  SilcPacketStream remote);
 void silc_server_announce_watches(SilcServer server,
-                                 SilcSocketConnection remote);
-bool silc_server_get_users_on_channel(SilcServer server,
+                                 SilcPacketStream remote);
+SilcBool silc_server_get_users_on_channel(SilcServer server,
                                      SilcChannelEntry channel,
                                      SilcBuffer *user_list,
                                      SilcBuffer *mode_list,
                                      SilcUInt32 *user_count);
 void silc_server_save_users_on_channel(SilcServer server,
-                                      SilcSocketConnection sock,
+                                      SilcPacketStream sock,
                                       SilcChannelEntry channel,
                                       SilcClientID *noadd,
                                       SilcBuffer user_list,
                                       SilcBuffer mode_list,
                                       SilcUInt32 user_count);
 void silc_server_save_user_channels(SilcServer server,
-                                   SilcSocketConnection sock,
+                                   SilcPacketStream sock,
                                    SilcClientEntry client,
                                    SilcBuffer channels,
                                    SilcBuffer channels_user_modes);
-SilcSocketConnection
+SilcPacketStream
 silc_server_get_client_route(SilcServer server,
                             unsigned char *id_data,
                             SilcUInt32 id_len,
@@ -250,8 +251,8 @@ silc_server_get_client_route(SilcServer server,
                             SilcClientEntry *client_entry);
 SilcBuffer silc_server_get_client_channel_list(SilcServer server,
                                               SilcClientEntry client,
-                                              bool get_private,
-                                              bool get_secret,
+                                              SilcBool get_private,
+                                              SilcBool get_secret,
                                               SilcBuffer *user_mode_list);
 void silc_server_stderr(SilcLogType type, char *message);
 
index 160997b5f0384e41077a4cd734953f68f04ea920..c52b3e3597a6651ebc440a5fef4d8b9cd0a2427f 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2005 Pekka Riikonen
+  Copyright (C) 2001 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -37,7 +37,7 @@ typedef struct {
   SilcServerEntry server;
   SilcIDIP ip;
   SilcUInt16 port;
-  bool local;
+  SilcBool local;
 } SilcServerBackupEntry;
 
 /* Holds IP address and port of the primary router that was replaced
@@ -58,14 +58,14 @@ struct SilcServerBackupStruct {
 
 typedef struct {
   SilcUInt8 session;
-  bool connected;
+  SilcBool connected;
   SilcServerEntry server_entry;
 } SilcServerBackupProtocolSession;
 
 /* Backup resuming protocol context  */
 typedef struct {
   SilcServer server;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   SilcUInt8 type;
   SilcUInt8 session;
   SilcServerBackupProtocolSession *sessions;
@@ -75,6 +75,7 @@ typedef struct {
   unsigned int responder        : 1;
   unsigned int received_failure : 1;
   unsigned int timeout          : 1;
+  unsigned int error            : 1;
 } *SilcServerBackupProtocolContext;
 
 
@@ -87,7 +88,7 @@ typedef struct {
    in the local cell, if FALSE it is in some other cell. */
 
 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
-                           const char *ip, int port, bool local)
+                           const char *ip, int port, SilcBool local)
 {
   int i;
 
@@ -107,8 +108,7 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
   }
 
   SILC_LOG_DEBUG(("Backup router %s will replace %s",
-                 ((SilcSocketConnection)backup_server->connection)->ip,
-                 ip, port));
+                 backup_server->data.sconn->remote_host, ip, port));
 
   for (i = 0; i < server->backup->servers_count; i++) {
     if (!server->backup->servers[i].server) {
@@ -253,9 +253,9 @@ void silc_server_backup_replaced_add(SilcServer server,
    and the bacup router entry to the `server' pointer if non-NULL. Returns
    FALSE if the router is not replaced by backup router. */
 
-bool silc_server_backup_replaced_get(SilcServer server,
-                                    SilcServerID *server_id,
-                                    SilcServerEntry *server_entry)
+SilcBool silc_server_backup_replaced_get(SilcServer server,
+                                        SilcServerID *server_id,
+                                        SilcServerEntry *server_entry)
 {
   int i;
 
@@ -307,14 +307,11 @@ void silc_server_backup_replaced_del(SilcServer server,
    that the caller already knows that the `packet' is broadcast packet. */
 
 void silc_server_backup_broadcast(SilcServer server,
-                                 SilcSocketConnection sender,
-                                 SilcPacketContext *packet)
+                                 SilcPacketStream sender,
+                                 SilcPacket packet)
 {
   SilcServerEntry backup;
-  SilcSocketConnection sock;
-  SilcBuffer buffer;
-  const SilcBufferStruct p;
-  SilcIDListData idata;
+  SilcPacketStream sock;
   int i;
 
   if (!server->backup || server->server_type != SILC_ROUTER)
@@ -322,9 +319,6 @@ void silc_server_backup_broadcast(SilcServer server,
 
   SILC_LOG_DEBUG(("Broadcasting received packet to backup routers"));
 
-  buffer = packet->buffer;
-  silc_buffer_push(buffer, buffer->data - buffer->head);
-
   for (i = 0; i < server->backup->servers_count; i++) {
     backup = server->backup->servers[i].server;
 
@@ -334,28 +328,8 @@ void silc_server_backup_broadcast(SilcServer server,
     if (server->backup->servers[i].server == server->id_entry)
       continue;
 
-    idata = (SilcIDListData)backup;
     sock = backup->connection;
-
-    if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
-                                 (const SilcBuffer)&p)) {
-      SILC_LOG_ERROR(("Cannot send packet"));
-      return;
-    }
-    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
-                       (SilcBuffer)&p, p.len);
-
-    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
-
-    /* Now actually send the packet */
-    silc_server_packet_send_real(server, sock, FALSE);
-
-    /* Check for mandatory rekey */
-    if (idata->psn_send == SILC_SERVER_REKEY_THRESHOLD)
-      silc_schedule_task_add(server->schedule, sender->sock,
-                            silc_server_rekey_callback, sender, 0, 1,
-                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_server_packet_route(server, sock, packet);
   }
 }
 
@@ -375,11 +349,11 @@ void silc_server_backup_send(SilcServer server,
                             SilcPacketFlags flags,
                             unsigned char *data,
                             SilcUInt32 data_len,
-                            bool force_send,
-                            bool local)
+                            SilcBool force_send,
+                            SilcBool local)
 {
   SilcServerEntry backup;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   int i;
 
   if (!server->backup || server->server_type != SILC_ROUTER)
@@ -396,11 +370,8 @@ void silc_server_backup_send(SilcServer server,
 
     sock = backup->connection;
 
-    SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
-                   silc_get_packet_name(type), sock->hostname, sock->ip));
-
     silc_server_packet_send(server, backup->connection, type, flags,
-                           data, data_len, force_send);
+                           data, data_len);
   }
 }
 
@@ -417,11 +388,11 @@ void silc_server_backup_send_dest(SilcServer server,
                                  SilcIdType dst_id_type,
                                  unsigned char *data,
                                  SilcUInt32 data_len,
-                                 bool force_send,
-                                 bool local)
+                                 SilcBool force_send,
+                                 SilcBool local)
 {
   SilcServerEntry backup;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   int i;
 
   if (!server->backup || server->server_type != SILC_ROUTER)
@@ -438,12 +409,8 @@ void silc_server_backup_send_dest(SilcServer server,
 
     sock = backup->connection;
 
-    SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
-                   silc_get_packet_name(type), sock->hostname, sock->ip));
-
     silc_server_packet_send_dest(server, backup->connection, type, flags,
-                                dst_id, dst_id_type, data, data_len,
-                                force_send);
+                                dst_id, dst_id_type, data, data_len);
   }
 }
 
@@ -452,24 +419,24 @@ void silc_server_backup_send_dest(SilcServer server,
    SILC_PACKET_RESUME_ROUTER. */
 
 void silc_server_backup_send_start_use(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      bool failure)
+                                      SilcPacketStream sock,
+                                      SilcBool failure)
 {
   unsigned char data[4];
 
-  SILC_LOG_DEBUG(("Sending START_USE (%s) to %s",
-                 failure ? "failure" : "success", sock->ip));
+  SILC_LOG_DEBUG(("Sending START_USE (%s)",
+                 failure ? "failure" : "success"));
 
   if (failure) {
     SILC_PUT32_MSB(SILC_SERVER_BACKUP_START_USE, data);
     silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
-                           data, 4, FALSE);
+                           data, 4);
   } else {
     data[0] = SILC_SERVER_BACKUP_START_USE;
     data[1] = 0;
     silc_server_packet_send(server, sock,
                            SILC_PACKET_RESUME_ROUTER, 0,
-                           data, 2, FALSE);
+                           data, 2);
   }
 }
 
@@ -478,17 +445,17 @@ void silc_server_backup_send_start_use(SilcServer server,
    online.  This is not sent by backup router or any other server. */
 
 void silc_server_backup_send_replaced(SilcServer server,
-                                     SilcSocketConnection sock)
+                                     SilcPacketStream sock)
 {
   unsigned char data[4];
 
-  SILC_LOG_DEBUG(("Sending REPLACED (%s) to %s", sock->ip));
+  SILC_LOG_DEBUG(("Sending REPLACED"));
 
   data[0] = SILC_SERVER_BACKUP_REPLACED;
   data[1] = 0;
   silc_server_packet_send(server, sock,
                          SILC_PACKET_RESUME_ROUTER, 0,
-                         data, 2, FALSE);
+                         data, 2);
 }
 
 
@@ -498,15 +465,15 @@ void silc_server_backup_send_replaced(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_backup_timeout)
 {
-  SilcProtocol protocol = context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = app_context;
 
   SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
   ctx->timeout = TRUE;
-  silc_protocol_cancel(protocol, server->schedule);
-  protocol->state = SILC_PROTOCOL_STATE_ERROR;
-  silc_protocol_execute_final(protocol, server->schedule);
+  ctx->error = TRUE;
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_protocol_backup_done, context,
+                                0, 0);
 }
 
 /* Callback to start the protocol as responder */
@@ -514,28 +481,28 @@ SILC_TASK_CALLBACK(silc_server_backup_timeout)
 SILC_TASK_CALLBACK(silc_server_backup_responder_start)
 {
   SilcServerBackupProtocolContext proto_ctx = context;
-  SilcSocketConnection sock = proto_ctx->sock;
+  SilcPacketStream sock = proto_ctx->sock;
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcServer server = app_context;
 
   /* If other protocol is executing at the same time, start with timeout. */
-  if (sock->protocol) {
+  if (idata->sconn->op) {
     SILC_LOG_DEBUG(("Other protocol is executing, wait for it to finish"));
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_backup_responder_start,
-                          proto_ctx, 2, 0,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_responder_start,
+                                  proto_ctx, 2, 0);
     return;
   }
 
+  /* Register protocol timeout */
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_backup_timeout,
+                                proto_ctx, 30, 0);
+
   /* Run the backup resuming protocol */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
-                     &sock->protocol, proto_ctx,
-                     silc_server_protocol_backup_done);
-  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_backup_timeout,
-                        sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_protocol_backup,
+                                proto_ctx, 0, 0);
 }
 
 /* Callback to send START_USE to backup to check whether using backup
@@ -543,7 +510,7 @@ SILC_TASK_CALLBACK(silc_server_backup_responder_start)
 
 SILC_TASK_CALLBACK(silc_server_backup_check_status)
 {
-  SilcSocketConnection sock = context;
+  SilcPacketStream sock = context;
   SilcServer server = app_context;
 
   /* Check whether we are still using backup */
@@ -551,13 +518,13 @@ SILC_TASK_CALLBACK(silc_server_backup_check_status)
     return;
 
   silc_server_backup_send_start_use(server, sock, FALSE);
-  silc_socket_free(sock);      /* unref */
+  silc_packet_stream_unref(sock);
 }
 
 typedef struct {
   SilcServer server;
-  SilcSocketConnection sock;
-  SilcPacketContext *packet;
+  SilcPacketStream sock;
+  SilcPacket packet;
 } *SilcServerBackupPing;
 
 /* PING command reply callback */
@@ -569,14 +536,12 @@ void silc_server_backup_ping_reply(void *context, void *reply)
 
   if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
     /* Timeout error occurred, the primary is really down. */
-    SilcSocketConnection primary = SILC_PRIMARY_ROUTE(pc->server);
+    SilcPacketStream primary = SILC_PRIMARY_ROUTE(pc->server);
 
     SILC_LOG_DEBUG(("PING timeout, primary is down"));
 
     if (primary) {
-      if (primary->user_data)
-       silc_server_free_sock_user_data(pc->server, primary, NULL);
-      SILC_SET_DISCONNECTING(primary);
+      silc_server_free_sock_user_data(pc->server, primary, NULL);
       silc_server_close_connection(pc->server, primary);
     }
 
@@ -588,8 +553,8 @@ void silc_server_backup_ping_reply(void *context, void *reply)
     silc_server_backup_send_start_use(pc->server, pc->sock, TRUE);
   }
 
-  silc_socket_free(pc->sock);
-  silc_packet_context_free(pc->packet);
+  silc_packet_stream_unref(pc->sock);
+  silc_packet_free(pc->packet);
   silc_free(pc);
 }
 
@@ -598,30 +563,30 @@ void silc_server_backup_ping_reply(void *context, void *reply)
    start command is received. */
 
 void silc_server_backup_resume_router(SilcServer server,
-                                     SilcSocketConnection sock,
-                                     SilcPacketContext *packet)
+                                     SilcPacketStream sock,
+                                     SilcPacket packet)
 {
+  SilcIDListData idata = silc_packet_get_context(sock);
   SilcUInt8 type, session;
   SilcServerBackupProtocolContext ctx;
-  SilcIDListData idata;
   int i, ret;
 
   SILC_LOG_DEBUG(("Received RESUME_ROUTER packet"));
 
-  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
-      sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
+  if (idata->conn_type == SILC_CONN_CLIENT ||
+      idata->conn_type == SILC_CONN_UNKNOWN) {
     SILC_LOG_DEBUG(("Bad packet received"));
+    silc_packet_free(packet);
     return;
   }
 
-  idata = (SilcIDListData)sock->user_data;
-
-  ret = silc_buffer_unformat(packet->buffer,
+  ret = silc_buffer_unformat(&packet->buffer,
                             SILC_STR_UI_CHAR(&type),
                             SILC_STR_UI_CHAR(&session),
                             SILC_STR_END);
   if (ret < 0) {
     SILC_LOG_ERROR(("Malformed resume router packet received"));
+    silc_packet_free(packet);
     return;
   }
 
@@ -636,6 +601,7 @@ void silc_server_backup_resume_router(SilcServer server,
     if (server->server_type == SILC_SERVER) {
       /* Nothing to do here actually, since we have switched already. */
       SILC_LOG_DEBUG(("Received successful START_USE from backup router"));
+      silc_packet_free(packet);
       return;
     }
 
@@ -644,16 +610,17 @@ void silc_server_backup_resume_router(SilcServer server,
     /* If we are marked as router then the primary is down and we send
        success START_USE back to the server. */
     if (server->server_type == SILC_ROUTER) {
-      SILC_LOG_DEBUG(("Sending success START_USE back to %s", sock->ip));
+      SILC_LOG_DEBUG(("Sending success START_USE back"));
       silc_server_backup_send_start_use(server, sock, FALSE);
+      silc_packet_free(packet);
       return;
     }
 
     /* We have just lost primary, send success START_USE back */
     if (server->standalone) {
-      SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back to %s",
-                     sock->ip));
+      SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back"));
       silc_server_backup_send_start_use(server, sock, FALSE);
+      silc_packet_free(packet);
       return;
     }
 
@@ -663,14 +630,15 @@ void silc_server_backup_resume_router(SilcServer server,
     idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
     silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
                             SILC_COMMAND_PING, ++server->cmd_ident, 1,
-                            1, idp->data, idp->len);
+                            1, idp->data, silc_buffer_len(idp));
     silc_buffer_free(idp);
 
     /* Reprocess this packet after received reply from router */
     pc = silc_calloc(1, sizeof(*pc));
     pc->server = server;
-    pc->sock = silc_socket_dup(sock);
-    pc->packet = silc_packet_context_dup(packet);
+    pc->sock = sock;
+    pc->packet = packet;
+    silc_packet_stream_ref(sock);
     silc_server_command_pending_timed(server, SILC_COMMAND_PING,
                                      server->cmd_ident,
                                      silc_server_backup_ping_reply, pc, 15);
@@ -695,36 +663,36 @@ void silc_server_backup_resume_router(SilcServer server,
                     "primary router"));
       SILC_PUT32_MSB(SILC_SERVER_BACKUP_START, data);
       silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
-                             data, 4, FALSE);
+                             data, 4);
       server->backup_closed = FALSE;
+      silc_packet_free(packet);
       return;
     }
 
     proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
     proto_ctx->server = server;
-    proto_ctx->sock = silc_socket_dup(sock);
+    proto_ctx->sock = sock;
     proto_ctx->responder = TRUE;
     proto_ctx->type = type;
     proto_ctx->session = session;
     proto_ctx->start = time(0);
+    silc_packet_stream_ref(sock);
 
     SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
     SILC_LOG_INFO(("Starting backup resuming protocol"));
 
     /* Start protocol immediately */
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_backup_responder_start,
-                          proto_ctx, 0, 1,
-                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_responder_start,
+                                  proto_ctx, 0, 1);
     return;
   }
 
-
   /* If we are router and the packet is coming from our primary router
      then it means we have been replaced by an backup router in our cell. */
   if (type == SILC_SERVER_BACKUP_REPLACED &&
       server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      idata->conn_type == SILC_CONN_ROUTER &&
       SILC_PRIMARY_ROUTE(server) == sock) {
     /* We have been replaced by an backup router in our cell. We must
        mark our primary router connection disabled since we are not allowed
@@ -732,20 +700,21 @@ void silc_server_backup_resume_router(SilcServer server,
     SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
                   "wait until backup resuming protocol is executed"));
     idata->status |= SILC_IDLIST_STATUS_DISABLED;
+    silc_packet_free(packet);
     return;
   }
 
-
+#if 0
   /* Activate the shared protocol context for this socket connection
      if necessary */
   if (type == SILC_SERVER_BACKUP_RESUMED &&
-      sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
+      idata->conn_type == SILC_CONN_ROUTER && !sock->protocol &&
       idata->status & SILC_IDLIST_STATUS_DISABLED) {
     SilcServerEntry backup_router;
 
     if (silc_server_backup_replaced_get(server, ((SilcServerEntry)idata)->id,
                                        &backup_router)) {
-      SilcSocketConnection bsock =
+      SilcPacketStream bsock =
        (SilcSocketConnection)backup_router->connection;
       if (bsock->protocol && bsock->protocol->protocol &&
          bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
@@ -768,6 +737,7 @@ void silc_server_backup_resume_router(SilcServer server,
       if (session == ctx->sessions[i].session) {
        ctx->session = session;
        silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+       silc_packet_free(packet);
        return;
       }
     }
@@ -775,120 +745,17 @@ void silc_server_backup_resume_router(SilcServer server,
     /* If RESUMED received the session ID is zero, execute the protocol. */
     if (type == SILC_SERVER_BACKUP_RESUMED) {
       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      silc_packet_free(packet);
       return;
     }
 
     SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
+    silc_packet_free(packet);
     return;
   }
-}
+#endif /* 0 */
 
-/* callback for async connection to remote router */
-
-SILC_TASK_CALLBACK(silc_server_backup_connection_established)
-{
-  SilcServer server = app_context;
-  SilcServerConnection sconn = (SilcServerConnection)context;
-  int sock = fd;
-  int opt = EINVAL, optlen = sizeof(opt);
-
-  silc_schedule_task_del_by_fd(server->schedule, sock);
-  silc_schedule_unset_listen_fd(server->schedule, sock);
-
-  if (silc_net_get_socket_opt(sock, SOL_SOCKET, SO_ERROR, &opt, &optlen) ||
-      (opt != 0)) {
-    SILC_LOG_DEBUG(("Could not connect to router %s:%d: %s", sconn->remote_host,
-                   sconn->remote_port, strerror(opt)));
-
-    if (server->server_type == SILC_SERVER) {
-      sconn->retry_count++;
-      if (sconn->retry_count > 3) {
-       silc_free(sconn->remote_host);
-       silc_free(sconn);
-       return;
-      }
-    }
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_backup_connect_to_router,
-                          context, 10, 0, SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Connection to router %s:%d established", sconn->remote_host,
-                 sconn->remote_port));
-
-  /* Continue with key exchange protocol */
-  silc_server_start_key_exchange(server, sconn, sock);
-}
-
-
-/* Timeout task callback to connect to remote router */
-
-SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
-{
-  SilcServer server = app_context;
-  SilcServerConnection sconn = (SilcServerConnection)context;
-  int sock;
-  const char *server_ip;
-
-  SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
-                 sconn->remote_port));
-
-  /* Connect to remote host */
-  server_ip = server->config->server_info->primary == NULL ? NULL :
-    server->config->server_info->primary->server_ip;
-  sock = silc_net_create_connection_async(server_ip, sconn->remote_port,
-                                         sconn->remote_host);
-  if (sock < 0) {
-    if (server->server_type == SILC_SERVER) {
-      sconn->retry_count++;
-      if (sconn->retry_count > 3) {
-       silc_free(sconn->remote_host);
-       silc_free(sconn);
-       return;
-      }
-    }
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_backup_connect_to_router,
-                          context, 10, 0, SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-    return;
-  }
-
-  /* wait for the connection to be established */
-  silc_schedule_task_add(server->schedule, sock,
-                        silc_server_backup_connection_established,
-                        context, 0, 0, SILC_TASK_FD,
-                        SILC_TASK_PRI_NORMAL);
-  silc_schedule_set_listen_fd(server->schedule, sock,
-                             SILC_TASK_WRITE, FALSE);
-}
-
-/* Constantly tries to reconnect to a primary router indicated by the
-   `ip' and `port'. The `connected' callback will be called when the
-   connection is created. */
-
-void silc_server_backup_reconnect(SilcServer server,
-                                 const char *ip, SilcUInt16 port,
-                                 SilcServerConnectRouterCallback callback,
-                                 void *context)
-{
-  SilcServerConnection sconn;
-
-  SILC_LOG_INFO(("Attempting to reconnect to primary router"));
-
-  sconn = silc_calloc(1, sizeof(*sconn));
-  sconn->remote_host = strdup(ip);
-  sconn->remote_port = port;
-  sconn->callback = callback;
-  sconn->callback_context = context;
-  sconn->no_reconnect = TRUE;
-  sconn->retry_count = 0;
-  silc_schedule_task_add(server->schedule, 0,
-                        silc_server_backup_connect_to_router,
-                        sconn, 1, 0, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_packet_free(packet);
 }
 
 /* Task that is called after backup router has connected back to
@@ -899,32 +766,36 @@ SILC_TASK_CALLBACK(silc_server_backup_connected_later)
   SilcServerBackupProtocolContext proto_ctx =
     (SilcServerBackupProtocolContext)context;
   SilcServer server = proto_ctx->server;
-  SilcSocketConnection sock = proto_ctx->sock;
-
-  /* If running other protocol already run this one a bit later. */
-  if (sock->protocol) {
-    SILC_LOG_DEBUG(("Other protocol is running, wait for it to finish"));
-    silc_schedule_task_add(server->schedule, 0,
-                          silc_server_backup_connected_later,
-                          proto_ctx, 15, 0,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-    return;
-  }
+  SilcPacketStream sock = proto_ctx->sock;
 
   SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
   SILC_LOG_INFO(("Starting backup resuming protocol"));
 
+  /* Register protocol timeout */
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_backup_timeout,
+                                proto_ctx, 30, 0);
+
   /* Run the backup resuming protocol */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
-                     &sock->protocol, proto_ctx,
-                     silc_server_protocol_backup_done);
-  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_backup_timeout,
-                        sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_protocol_backup,
+                                proto_ctx, 0, 0);
+}
+
+SILC_TASK_CALLBACK(silc_server_backup_connected_again)
+{
+  SilcServer server = app_context;
+  SilcServerConfigRouter *primary;
+
+  primary = silc_server_config_get_primary_router(server);
+  if (primary) {
+    if (!silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+                                        primary->host, primary->port))
+      silc_server_create_connection(server, FALSE,
+                                   primary->host, primary->port,
+                                   silc_server_backup_connected,
+                                   context);
+  }
 }
 
 /* Called when we've established connection back to our primary router
@@ -936,37 +807,45 @@ void silc_server_backup_connected(SilcServer server,
                                  void *context)
 {
   SilcServerBackupProtocolContext proto_ctx;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
 
   if (!server_entry) {
     /* Try again */
-    SilcServerConfigRouter *primary;
-    primary = silc_server_config_get_primary_router(server);
-    if (primary) {
-      if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
-                                          primary->host, primary->port))
-       silc_server_backup_reconnect(server,
-                                    primary->host, primary->port,
-                                    silc_server_backup_connected,
-                                    context);
-    }
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_connected_again,
+                                  context, 0, 0);
     return;
   }
 
-  sock = (SilcSocketConnection)server_entry->connection;
+  sock = server_entry->connection;
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
   proto_ctx->server = server;
-  proto_ctx->sock = silc_socket_dup(sock);
+  proto_ctx->sock = sock;
   proto_ctx->responder = FALSE;
   proto_ctx->type = SILC_SERVER_BACKUP_START;
   proto_ctx->start = time(0);
+  silc_packet_stream_ref(sock);
 
   /* Start through scheduler */
-  silc_schedule_task_add(server->schedule, 0,
-                        silc_server_backup_connected_later,
-                        proto_ctx, 0, 1,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_backup_connected_later,
+                                proto_ctx, 0, 1);
+}
+
+SILC_TASK_CALLBACK(silc_server_backup_connect_primary_again)
+{
+  SilcServer server = app_context;
+  SilcServerConfigRouter *primary;
+
+  primary = silc_server_config_get_primary_router(server);
+  if (primary) {
+    if (!silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
+                                        primary->host, primary->port))
+      silc_server_create_connection(server, FALSE,
+                                   primary->host, primary->port,
+                                   silc_server_backup_connect_primary,
+                                   context);
+  }
 }
 
 /* Called when normal server has connected to its primary router after
@@ -978,34 +857,23 @@ static void silc_server_backup_connect_primary(SilcServer server,
                                               SilcServerEntry server_entry,
                                               void *context)
 {
-  SilcSocketConnection backup_router = (SilcSocketConnection)context;
+#if 0
+  SilcPacketStream backup_router = context;
   SilcServerBackupProtocolContext ctx;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   SilcIDListData idata;
   unsigned char data[2];
 
-  if (SILC_IS_DISCONNECTING(backup_router) ||
-      SILC_IS_DISCONNECTED(backup_router)) {
-    silc_socket_free(backup_router);
-    return;
-  }
-
   if (!server_entry) {
     /* Try again */
-    SilcServerConfigRouter *primary;
-    primary = silc_server_config_get_primary_router(server);
-    if (primary)
-      if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
-                                          primary->host, primary->port))
-       silc_server_backup_reconnect(server,
-                                    primary->host, primary->port,
-                                    silc_server_backup_connect_primary,
-                                    context);
+    silc_schedule_task_add_timeout(server->schedule,
+                                  silc_server_backup_connect_primary_again,
+                                  context, 0, 0);
     return;
   }
 
   /* Unref */
-  silc_socket_free(backup_router);
+  silc_packet_stream_unref(backup_router);
 
   if (!backup_router->protocol)
     return;
@@ -1039,6 +907,7 @@ static void silc_server_backup_connect_primary(SilcServer server,
     silc_socket_free(ctx->sock); /* unref */
   ctx->sock = silc_socket_dup(server_entry->connection);
   backup_router->protocol = NULL;
+#endif /* 0 */x
 }
 
 /* Timeout callback used by the backup router to send the ENDING packet
@@ -1047,8 +916,8 @@ static void silc_server_backup_connect_primary(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
 {
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+#if 0
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = ctx->server;
   unsigned char data[2];
   int i;
@@ -1064,22 +933,23 @@ SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
   data[0] = SILC_SERVER_BACKUP_ENDING;
   data[1] = ctx->session;
   silc_server_packet_send(server, ctx->sock, SILC_PACKET_RESUME_ROUTER, 0,
-                         data, sizeof(data), FALSE);
+                         data, sizeof(data));
 
   /* The protocol will go to END state. */
   protocol->state = SILC_PROTOCOL_STATE_END;
+#endif /* 0 */
 }
 
 /* Backup resuming protocol. This protocol is executed when the primary
    router wants to resume its position as being primary router. */
 
-SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
+SILC_TASK_CALLBACK(silc_server_protocol_backup)
 {
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+#if 0
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = ctx->server;
   SilcServerEntry server_entry;
-  SilcSocketConnection sock = NULL;
+  SilcPacketStream sock = NULL;
   unsigned char data[2];
   int i;
 
@@ -1101,8 +971,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        sock = server->sockets[i];
        if (!sock || !sock->user_data ||
            sock->user_data == server->id_entry ||
-           (sock->type != SILC_SOCKET_TYPE_ROUTER &&
-            sock->type != SILC_SOCKET_TYPE_SERVER))
+           (sock->type != SILC_CONN_ROUTER &&
+            sock->type != SILC_CONN_SERVER))
          continue;
 
        server_entry = sock->user_data;
@@ -1161,13 +1031,13 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                                             silc_net_is_ip(primary->host) ?
                                             NULL : primary->host,
                                             primary->port,
-                                            SILC_SOCKET_TYPE_ROUTER)) {
+                                            SILC_CONN_ROUTER)) {
        SILC_LOG_DEBUG(("Received START (session %d), reconnect to router",
                        ctx->session));
-       silc_server_backup_reconnect(server,
-                                    primary->host, primary->port,
-                                    silc_server_backup_connect_primary,
-                                    silc_socket_dup(ctx->sock));
+       silc_server_create_connection(server, FALSE;
+                                     primary->host, primary->port,
+                                     silc_server_backup_connect_primary,
+                                     silc_socket_dup(ctx->sock));
       } else {
        /* Nowhere to connect just return the CONNECTED packet */
        SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
@@ -1270,8 +1140,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        sock = server->sockets[i];
        if (!sock || !sock->user_data ||
            sock->user_data == server->id_entry ||
-           (sock->type != SILC_SOCKET_TYPE_ROUTER &&
-            sock->type != SILC_SOCKET_TYPE_SERVER))
+           (sock->type != SILC_CONN_ROUTER &&
+            sock->type != SILC_CONN_SERVER))
          continue;
 
        /* Send to backup last */
@@ -1292,7 +1162,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        data[1] = 0;
        silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
                                data, sizeof(data), FALSE);
-       silc_server_packet_queue_purge(server, sock);
       }
 
       /* Now send the same packet to backup */
@@ -1408,24 +1277,24 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
   }
+#endif /* 0 */
 }
 
 /* Final resuming protocol completion callback */
 
 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
 {
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerBackupProtocolContext ctx = protocol->context;
+#if 0
+  SilcServerBackupProtocolContext ctx = context;
   SilcServer server = ctx->server;
   SilcServerEntry server_entry;
-  SilcSocketConnection sock;
-  bool error;
+  SilcPacketStream sock;
+  SilcBool error;
   int i;
 
   silc_schedule_task_del_by_context(server->schedule, protocol);
 
-  error = (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-          protocol->state == SILC_PROTOCOL_STATE_FAILURE);
+  error = ctx->error;
 
   if (error) {
     SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
@@ -1441,8 +1310,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
   for (i = 0; i < server->config->param.connections_max; i++) {
     sock = server->sockets[i];
     if (!sock || !sock->user_data ||
-       (sock->type != SILC_SOCKET_TYPE_ROUTER &&
-        sock->type != SILC_SOCKET_TYPE_SERVER))
+       (sock->type != SILC_CONN_ROUTER &&
+        sock->type != SILC_CONN_SERVER))
       continue;
 
     server_entry = sock->user_data;
@@ -1450,7 +1319,6 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
     /* The SilcProtocol context was shared between all connections, clear
        it from all connections. */
     if (sock->protocol == protocol) {
-      silc_server_packet_queue_purge(server, sock);
       sock->protocol = NULL;
 
       if (error) {
@@ -1579,13 +1447,16 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
   silc_protocol_free(protocol);
   silc_free(ctx->sessions);
   silc_free(ctx);
+#endif /* 0 */
 }
 
 SILC_TASK_CALLBACK(silc_server_backup_announce_watches)
 {
-  SilcSocketConnection sock = context;
+#if 0
+  SilcPacketStream sock = context;
   SilcServer server = app_context;
   if (sock->users > 1)
     silc_server_announce_watches(server, sock);
   silc_socket_free(sock);
+#endif /* 0 */
 }
index e6ea92259bbe7328aa45f2cc796a2c9ea3512182..79684a6793b0e44cdc801fb68008563e0dce9576 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2003 Pekka Riikonen
+  Copyright (C) 2001 - 2003, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@
    will become unresponsive. If `local' is TRUE then the `backup_server' is
    in the local cell, if FALSE it is in some other cell. */
 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
-                           const char *ip, int port, bool local);
+                           const char *ip, int port, SilcBool local);
 
 /* Returns backup router for IP and port in `server_id' or NULL if there
    does not exist backup router. */
@@ -61,7 +61,7 @@ void silc_server_backup_replaced_add(SilcServer server,
    replaced by an backup router. If it has been then this returns TRUE
    and the bacup router entry to the `server' pointer if non-NULL. Returns
    FALSE if the router is not replaced by backup router. */
-bool silc_server_backup_replaced_get(SilcServer server,
+SilcBool silc_server_backup_replaced_get(SilcServer server,
                                     SilcServerID *server_id,
                                     SilcServerEntry *server_entry);
 
@@ -74,8 +74,8 @@ void silc_server_backup_replaced_del(SilcServer server,
    That is why all backup routers need to get this data too. It is expected
    that the caller already knows that the `packet' is broadcast packet. */
 void silc_server_backup_broadcast(SilcServer server,
-                                 SilcSocketConnection sender,
-                                 SilcPacketContext *packet);
+                                 SilcPacketStream sender,
+                                 SilcPacket packet);
 
 /* A generic routine to send data to all backup routers. If the `sender'
    is provided it will indicate the original sender of the packet and the
@@ -92,8 +92,8 @@ void silc_server_backup_send(SilcServer server,
                             SilcPacketFlags flags,
                             unsigned char *data,
                             SilcUInt32 data_len,
-                            bool force_send,
-                            bool local);
+                            SilcBool force_send,
+                            SilcBool local);
 
 /* Same as silc_server_backup_send but sets a specific Destination ID to
    the packet. The Destination ID is indicated by the `dst_id' and the
@@ -107,36 +107,28 @@ void silc_server_backup_send_dest(SilcServer server,
                                  SilcIdType dst_id_type,
                                  unsigned char *data,
                                  SilcUInt32 data_len,
-                                 bool force_send,
-                                 bool local);
+                                 SilcBool force_send,
+                                 SilcBool local);
 
 /* Send the START_USE indication to remote connection.  If `failure' is
    TRUE then this sends SILC_PACKET_FAILURE.  Otherwise it sends
    SILC_PACKET_RESUME_ROUTER. */
 void silc_server_backup_send_start_use(SilcServer server,
-                                      SilcSocketConnection sock,
-                                      bool failure);
+                                      SilcPacketStream sock,
+                                      SilcBool failure);
 
 /* Send the REPLACED indication to remote router.  This is send by the
    primary router (remote router) of the primary router that came back
    online.  This is not sent by backup router or any other server. */
 void silc_server_backup_send_replaced(SilcServer server,
-                                     SilcSocketConnection sock);
+                                     SilcPacketStream sock);
 
 /* Processes incoming RESUME_ROUTER packet. This can give the packet
    for processing to the protocol handler or allocate new protocol if
    start command is received. */
 void silc_server_backup_resume_router(SilcServer server,
-                                     SilcSocketConnection sock,
-                                     SilcPacketContext *packet);
-
-/* Constantly tries to reconnect to a primary router indicated by the
-   `ip' and `port'. The `connected' callback will be called when the
-   connection is created. */
-void silc_server_backup_reconnect(SilcServer server,
-                                 const char *ip, SilcUInt16 port,
-                                 SilcServerConnectRouterCallback callback,
-                                 void *context);
+                                     SilcPacketStream sock,
+                                     SilcPacket packet);
 
 /* Called when we've established connection back to our primary router
    when we've acting as backup router and have replaced the primary router
@@ -147,6 +139,6 @@ void silc_server_backup_connected(SilcServer server,
 
 /* Backup resuming protocol. This protocol is executed when the primary
    router wants to resume its position as being primary router. */
-SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup);
+SILC_TASK_CALLBACK(silc_server_protocol_backup);
 
 #endif /* SERVER_BACKUP_H */
index b92f80f3471daf9928a9aa009bd08ded54b39f4a..0870b9da1b3b46842704e85298f7d733b8480ebc 100644 (file)
@@ -71,7 +71,6 @@ typedef struct {
 */
 struct SilcServerStruct {
   char *server_name;
-  int sock;
   SilcServerEntry id_entry;
   SilcServerID *id;
   unsigned char *id_string;
@@ -96,6 +95,8 @@ struct SilcServerStruct {
   unsigned int server_shutdown: 1;   /* Set when shutting down */
   unsigned int no_reconnect   : 1;   /* If set, server won't reconnect to
                                        router after disconnection. */
+  unsigned int no_conf        : 1;   /* Set when connecting without
+                                       configuration. */
 
   SilcServerEntry router;           /* Pointer to the primary router */
   unsigned long router_connect;             /* Time when router was connected */
@@ -115,11 +116,15 @@ struct SilcServerStruct {
   SilcHashTable watcher_list;
   SilcHashTable watcher_list_pk;
 
+  SilcDList listeners;              /* TCP listeners */
+  SilcPacketEngine packet_engine;    /* Packet engine */
+  SilcDList conns;
+  SilcSKR repository;
+
   /* Table of connected sockets */
-  SilcSocketConnection *sockets;
+  SilcPacketStream *sockets;
 
   /* Server public key */
-  SilcPKCS pkcs;
   SilcPublicKey public_key;
   SilcPrivateKey private_key;
 
@@ -145,11 +150,6 @@ struct SilcServerStruct {
   SilcIDListPurge purge_i;
   SilcIDListPurge purge_g;
 
-#ifdef SILC_SIM
-  /* SIM (SILC Module) list */
-  SilcDList sim;
-#endif
-
   /* Hash table for public keys of all clients */
   SilcHashTable pk_hash;
 };
@@ -158,7 +158,7 @@ struct SilcServerStruct {
    Failure packets are processed with timeout and data is saved in this
    structure. */
 typedef struct {
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
   SilcUInt32 failure;
 } *SilcServerFailureContext;
 
@@ -234,15 +234,20 @@ do {                                              \
 #define SILC_GET_SKE_FLAGS(x, p)                       \
   if ((x)) {                                           \
     if ((x)->param && (x)->param->key_exchange_pfs)    \
-      (p)->flags |= SILC_SKE_SP_FLAG_PFS;              \
+      (p) |= SILC_SKE_SP_FLAG_PFS;                     \
     if (!(x)->publickeys)                              \
-      (p)->flags |= SILC_SKE_SP_FLAG_MUTUAL;           \
+      (p) |= SILC_SKE_SP_FLAG_MUTUAL;                  \
   }
 
+#define SILC_CONNTYPE_STRING(ctype)                    \
+  (ctype == SILC_CONN_CLIENT ? "Client" :              \
+   ctype == SILC_CONN_SERVER ? "Server" :              \
+   ctype == SILC_CONN_ROUTER ? "Router" : "Unknown")
+
 /* Prototypes */
-SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final);
-SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback);
-SILC_TASK_CALLBACK_GLOBAL(silc_server_connect_to_router);
+SILC_TASK_CALLBACK(silc_server_rekey_final);
+SILC_TASK_CALLBACK(silc_server_rekey_callback);
+SILC_TASK_CALLBACK(silc_server_connect_to_router);
 void silc_server_watcher_list_destroy(void *key, void *context,
                                      void *user_context);
 
index b9b769713e601c1e3849d5a1c93fbe397a1edb5d..6b0f1dcd95d2fa10180694c6307befb0164978b4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 - 2005 Pekka Riikonen
+  Copyright (C) 2002 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 #include "server_internal.h"
 
 typedef struct {
-  SilcSocketConnection sock;       /* Connection of this query */
+  SilcPacketStream sock;           /* Connection of this query */
   unsigned char **arg;             /* Query argument */
   SilcUInt32 *arg_lens;                    /* Query argument lengths */
   SilcUInt32 *arg_types;           /* Query argument types */
@@ -51,8 +51,8 @@ typedef struct {
 /* Query session context */
 typedef struct {
   /* Queried data */
-  char *nickname;                  /* Queried nickname, normalized */
-  char *nick_server;               /* Queried nickname's server */
+  char nickname[128 + 1];          /* Queried nickname, normalized */
+  char nick_server[128 + 1];       /* Queried nickname's server */
   char *server_name;               /* Queried server name, normalized */
   char *channel_name;              /* Queried channel name, normalized */
   SilcServerQueryID ids;           /* Queried IDs */
@@ -91,9 +91,9 @@ void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
 void silc_server_query_send_router_reply(void *context, void *reply);
 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
 void silc_server_query_process(SilcServer server, SilcServerQuery query,
-                              bool resolve);
+                              SilcBool resolve);
 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
-                              SilcSocketConnection sock,
+                              SilcPacketStream sock,
                               SilcClientEntry client_entry);
 void silc_server_query_resolve_reply(void *context, void *reply);
 void silc_server_query_send_reply(SilcServer server,
@@ -120,8 +120,6 @@ void silc_server_query_free(SilcServerQuery query)
     silc_free(query->queries[i].id);
   silc_free(query->queries);
 
-  silc_free(query->nickname);
-  silc_free(query->nick_server);
   silc_free(query->server_name);
   silc_free(query->channel_name);
 
@@ -222,7 +220,7 @@ void silc_server_query_add_error_id(SilcServer server,
    to the entity who sent this query to us automatically.  Returns
    TRUE if the query is being processed or FALSE on error. */
 
-bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
+SilcBool silc_server_query_command(SilcServer server, SilcCommand querycmd,
                               SilcServerCommandContext cmd)
 {
   SilcServerQuery query;
@@ -304,7 +302,7 @@ void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
   silc_server_packet_send(server,
                          SILC_PRIMARY_ROUTE(server),
                          SILC_PACKET_COMMAND, 0,
-                         tmpbuf->data, tmpbuf->len, TRUE);
+                         tmpbuf->data, silc_buffer_len(tmpbuf));
   silc_command_set_ident(query->cmd->payload, old_ident);
   silc_buffer_free(tmpbuf);
 
@@ -327,7 +325,7 @@ void silc_server_query_send_router_reply(void *context, void *reply)
   SILC_LOG_DEBUG(("Received reply from router to query"));
 
   /* If the original command caller has gone away, just stop. */
-  if (query->cmd->sock->users == 1) {
+  if (!silc_packet_stream_is_valid(query->cmd->sock)) {
     SILC_LOG_DEBUG(("Original command caller vanished"));
     silc_server_query_free(query);
     return;
@@ -349,7 +347,7 @@ void silc_server_query_send_router_reply(void *context, void *reply)
     buffer = silc_command_payload_encode_payload(cmdr->payload);
     silc_server_packet_send(server, query->cmd->sock,
                            SILC_PACKET_COMMAND_REPLY, 0,
-                           buffer->data, buffer->len, FALSE);
+                           buffer->data, silc_buffer_len(buffer));
     silc_buffer_free(buffer);
     silc_server_query_free(query);
     return;
@@ -364,10 +362,10 @@ void silc_server_query_send_router_reply(void *context, void *reply)
 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
 {
   SilcServerCommandContext cmd = query->cmd;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   unsigned char *tmp;
   SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
-  void *id;
-  SilcIdType id_type;
+  SilcID id;
   int i;
 
   SILC_LOG_DEBUG(("Parsing %s query",
@@ -384,9 +382,8 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
       /* When Requested Attributes is present we will assure that this
         client cannot execute the WHOIS command too fast.  This would be
         same as having SILC_CF_LAG_STRICT. */
-      if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-          cmd->sock->user_data)
-       ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
+      if (idata && idata->conn_type == SILC_CONN_CLIENT)
+       ((SilcClientEntry)idata)->fast_command = 6;
     }
 
     /* Get Client IDs if present. Take IDs always instead of nickname. */
@@ -405,7 +402,10 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
 
       /* Get the nickname@server string and parse it */
       if (tmp && ((tmp_len > 128) ||
-         !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
+                 !silc_parse_userfqdn(tmp, query->nickname,
+                                      sizeof(query->nickname),
+                                      query->nick_server,
+                                      sizeof(query->nick_server)))) {
        silc_server_query_send_error(server, query,
                                     SILC_STATUS_ERR_BAD_NICKNAME, 0);
        silc_server_query_free(query);
@@ -422,8 +422,9 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
          silc_server_query_free(query);
          return;
        }
-       silc_free(query->nickname);
-       query->nickname = tmp;
+       memset(query->nickname, 0, sizeof(query->nickname));
+       silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
+       silc_free(tmp);
       }
 
     } else {
@@ -435,8 +436,8 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
        if (!tmp)
          continue;
 
-       id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-       if (!id || id_type != SILC_ID_CLIENT) {
+       if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
+           id.type != SILC_ID_CLIENT) {
          silc_server_query_add_error(server, query, 1, i + 4,
                                      SILC_STATUS_ERR_BAD_CLIENT_ID);
          continue;
@@ -446,23 +447,23 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
           send the query to router, unless done so already */
        if (server->server_type == SILC_SERVER && !query->resolved) {
          if (!silc_idlist_find_client_by_id(server->local_list,
-                                            id, TRUE, NULL)) {
-           if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
+                                            &id.u.client_id, TRUE, NULL)) {
+           if (idata->conn_type != SILC_CONN_CLIENT ||
                !silc_idlist_find_client_by_id(server->global_list,
-                                              id, TRUE, NULL)) {
+                                              &id.u.client_id, TRUE, NULL)) {
              silc_server_query_send_router(server, query);
              for (i = 0; i < query->ids_count; i++)
                silc_free(query->ids[i].id);
              silc_free(query->ids);
              query->ids = NULL;
              query->ids_count = 0;
-             silc_free(id);
              return;
            }
          }
        }
 
-       query->ids[query->ids_count].id = id;
+       query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
+                                                     SILC_ID_CLIENT);
        query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
        query->ids_count++;
       }
@@ -486,7 +487,8 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
 
     /* Get the nickname@server string and parse it */
     if (tmp_len > 128 ||
-       !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
+       !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
+                            query->nick_server, sizeof(query->nick_server))) {
       silc_server_query_send_error(server, query,
                                   SILC_STATUS_ERR_BAD_NICKNAME, 0);
       silc_server_query_free(query);
@@ -502,8 +504,9 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
       silc_server_query_free(query);
       return;
     }
-    silc_free(query->nickname);
-    query->nickname = tmp;
+    memset(query->nickname, 0, sizeof(query->nickname));
+    silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
+    silc_free(tmp);
 
     /* Get the max count of reply messages allowed */
     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
@@ -521,7 +524,10 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
       if (tmp) {
        /* Get the nickname@server string and parse it */
        if (tmp_len > 128 ||
-           !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
+           !silc_parse_userfqdn(tmp, query->nickname,
+                                sizeof(query->nickname),
+                                query->nick_server,
+                                sizeof(query->nick_server)))
          silc_server_query_add_error(server, query, 1, 1,
                                      SILC_STATUS_ERR_BAD_NICKNAME);
 
@@ -534,8 +540,9 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
          silc_server_query_free(query);
          return;
        }
-       silc_free(query->nickname);
-       query->nickname = tmp;
+       memset(query->nickname, 0, sizeof(query->nickname));
+       silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
+       silc_free(tmp);
       }
 
       /* Try get server name */
@@ -568,7 +575,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
        query->channel_name = tmp;
       }
 
-      if (!query->nickname && !query->server_name && !query->channel_name) {
+      if (!query->nickname[0] && !query->server_name && !query->channel_name) {
        silc_server_query_send_error(server, query,
                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
        silc_server_query_free(query);
@@ -584,8 +591,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
        if (!tmp)
          continue;
 
-       id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-       if (!id) {
+       if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
          silc_server_query_add_error(server, query, 1, i + 5,
                                      SILC_STATUS_ERR_BAD_CLIENT_ID);
          continue;
@@ -594,19 +600,19 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
        /* Normal server must check whether this ID exist, and if not then
           send the query to router, unless done so already */
        if (server->server_type == SILC_SERVER && !query->resolved) {
-         if (id_type == SILC_ID_CLIENT) {
+         if (id.type == SILC_ID_CLIENT) {
            if (!silc_idlist_find_client_by_id(server->local_list,
-                                              id, TRUE, NULL)) {
-             if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
+                                              &id.u.client_id, TRUE, NULL)) {
+             if (idata->conn_type != SILC_CONN_CLIENT ||
                  !silc_idlist_find_client_by_id(server->global_list,
-                                                id, TRUE, NULL)) {
+                                                &id.u.client_id, TRUE,
+                                                NULL)) {
                silc_server_query_send_router(server, query);
                for (i = 0; i < query->ids_count; i++)
                  silc_free(query->ids[i].id);
                silc_free(query->ids);
                query->ids = NULL;
                query->ids_count = 0;
-               silc_free(id);
                return;
              }
            }
@@ -619,13 +625,20 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
            silc_free(query->ids);
            query->ids = NULL;
            query->ids_count = 0;
-           silc_free(id);
            return;
          }
        }
 
-       query->ids[query->ids_count].id = id;
-       query->ids[query->ids_count].id_type = id_type;
+       if (id.type == SILC_ID_CLIENT)
+         query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
+                                                       SILC_ID_CLIENT);
+       if (id.type == SILC_ID_SERVER)
+         query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
+                                                       SILC_ID_SERVER);
+       if (id.type == SILC_ID_CHANNEL)
+         query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
+                                                       SILC_ID_CHANNEL);
+       query->ids[query->ids_count].id_type = id.type;
        query->ids_count++;
       }
     }
@@ -645,7 +658,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query)
 typedef struct {
   SilcClientEntry **clients;
   SilcUInt32 *clients_count;
-  bool found;
+  SilcBool found;
 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
 
 void silc_server_public_key_hash_foreach(void *key, void *context,
@@ -679,14 +692,15 @@ void silc_server_query_check_attributes(SilcServer server,
   SilcAttribute attribute;
   SilcAttributeObjPk pk;
   SilcPublicKey publickey;
+  SilcPKCSType type;
+  SilcBool found = FALSE, no_clients = FALSE;
   int i;
-  bool found = FALSE, no_clients = FALSE;
 
   /* If no clients were found, we only check the attributes
      if the user wasn't searching for nickname/ids */
   if (!(*clients)) {
     no_clients = TRUE;
-    if (query->nickname || query->ids_count)
+    if (query->nickname[0] || query->ids_count)
       return;
   }
 
@@ -701,8 +715,19 @@ void silc_server_query_check_attributes(SilcServer server,
        if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
          continue;
 
-       if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
-                                        &publickey)) {
+       if (!strcmp(pk.type, "silc-rsa"))
+         type = SILC_PKCS_SILC;
+       else if (!strcmp(pk.type, "ssh-rsa"))
+         type = SILC_PKCS_SSH2;
+       else if (!strcmp(pk.type, "x509v3-sign-rsa"))
+         type = SILC_PKCS_X509V3;
+       else if (!strcmp(pk.type, "pgp-sign-rsa"))
+         type = SILC_PKCS_OPENPGP;
+       else
+         continue;
+
+       if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
+                                       &publickey)) {
          silc_free(pk.type);
          silc_free(pk.data);
          continue;
@@ -745,7 +770,7 @@ void silc_server_query_check_attributes(SilcServer server,
     }
   }
 
-  if (!found && !query->nickname && !query->ids)
+  if (!found && !query->nickname[0] && !query->ids)
     silc_server_query_add_error(server, query, 2, 0,
                                 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
 }
@@ -755,10 +780,11 @@ void silc_server_query_check_attributes(SilcServer server,
    sender of the query command. */
 
 void silc_server_query_process(SilcServer server, SilcServerQuery query,
-                              bool resolve)
+                              SilcBool resolve)
 {
   SilcServerCommandContext cmd = query->cmd;
-  bool check_global = FALSE;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
+  SilcBool check_global = FALSE;
   void *entry;
   SilcClientEntry *clients = NULL, client_entry;
   SilcChannelEntry *channels = NULL;
@@ -771,12 +797,12 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query,
 
   /* Check global lists if query is coming from client or we are not
      normal server (we know global information). */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+  if (idata->conn_type == SILC_CONN_CLIENT)
     check_global = TRUE;
   else if (server->server_type != SILC_SERVER)
     check_global = TRUE;
 
-  if (query->nickname) {
+  if (query->nickname[0]) {
     /* Get all clients matching nickname from local list */
     if (!silc_idlist_get_clients_by_hash(server->local_list,
                                         query->nickname, server->md5hash,
@@ -784,6 +810,7 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query,
       silc_idlist_get_clients_by_nickname(server->local_list,
                                          query->nickname,
                                          query->nick_server,
+                                        /* XXX nick_server may not be set */
                                          &clients, &clients_count);
 
     /* Check global list as well */
@@ -794,6 +821,7 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query,
        silc_idlist_get_clients_by_nickname(server->global_list,
                                            query->nickname,
                                            query->nick_server,
+                                        /* XXX nick_server may not be set */
                                            &clients, &clients_count);
     }
 
@@ -1064,7 +1092,7 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query,
    client entry calls this function to do the resolving. */
 
 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
-                              SilcSocketConnection sock,
+                              SilcPacketStream sock,
                               SilcClientEntry client_entry)
 {
   SilcServerCommandContext cmd = query->cmd;
@@ -1116,7 +1144,7 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
                                            r->argc, r->arg, r->arg_lens,
                                            r->arg_types, r->ident);
       silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
-                             res_cmd->data, res_cmd->len, FALSE);
+                             res_cmd->data, silc_buffer_len(res_cmd));
       silc_buffer_free(res_cmd);
 
       /* Reprocess this packet after received reply */
@@ -1187,8 +1215,8 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
 
       /* Add the client entry to be resolved */
       idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
-      r->arg[r->argc] = silc_memdup(idp->data, idp->len);
-      r->arg_lens[r->argc] = idp->len;
+      r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
+      r->arg_lens[r->argc] = silc_buffer_len(idp);
       r->arg_types[r->argc] = r->argc + 4;
       r->argc++;
       silc_buffer_free(idp);
@@ -1300,7 +1328,7 @@ void silc_server_query_resolve_reply(void *context, void *reply)
   SILC_LOG_DEBUG(("Reprocess the query"));
 
   /* If the original command caller has gone away, just stop. */
-  if (query->cmd->sock->users == 1) {
+  if (!silc_packet_stream_is_valid(query->cmd->sock)) {
     SILC_LOG_DEBUG(("Original command caller vanished"));
     silc_server_query_free(query);
     return;
@@ -1333,6 +1361,7 @@ void silc_server_query_send_reply(SilcServer server,
                                  SilcUInt32 channels_count)
 {
   SilcServerCommandContext cmd = query->cmd;
+  SilcIDListData idata = silc_packet_get_context(cmd->sock);
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   SilcStatus status;
   unsigned char *tmp;
@@ -1340,7 +1369,7 @@ void silc_server_query_send_reply(SilcServer server,
   SilcBuffer idp;
   int i, k, valid_count;
   char nh[384], uh[384];
-  bool sent_reply = FALSE;
+  SilcBool sent_reply = FALSE;
 
   SILC_LOG_DEBUG(("Sending reply to query"));
   SILC_LOG_DEBUG(("Sending %d clients", clients_count));
@@ -1353,7 +1382,7 @@ void silc_server_query_send_reply(SilcServer server,
   /* Send clients */
   if (clients_count) {
     SilcClientEntry entry;
-    SilcSocketConnection hsock;
+    SilcPacketStream hsock;
 
     /* Mark all invalid entries */
     for (i = 0, valid_count = 0; i < clients_count; i++) {
@@ -1461,11 +1490,12 @@ void silc_server_query_send_reply(SilcServer server,
          if (!strchr(entry->username, '@') && entry->connection) {
            hsock = entry->connection;
            silc_strncat(uh, sizeof(uh), "@", 1);
-           len = strlen(hsock->hostname);
-           silc_strncat(uh, sizeof(uh), hsock->hostname, len);
+           silc_socket_stream_get_info(hsock, NULL, (const char **)&tmp,
+                                       NULL, NULL);
+           silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
          }
 
-         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+         if (idata->conn_type == SILC_CONN_CLIENT)
            channels =
              silc_server_get_client_channel_list(server, entry, FALSE,
                                                  FALSE, &umode_list);
@@ -1500,19 +1530,21 @@ void silc_server_query_send_reply(SilcServer server,
          /* Send command reply */
          silc_server_send_command_reply(server, cmd->sock, query->querycmd,
                                         status, 0, ident, 10,
-                                        2, idp->data, idp->len,
+                                        2, idp->data, silc_buffer_len(idp),
                                         3, nh, strlen(nh),
                                         4, uh, strlen(uh),
                                         5, entry->userinfo,
                                         strlen(entry->userinfo),
                                         6, channels ? channels->data : NULL,
-                                        channels ? channels->len : 0,
+                                        channels ? silc_buffer_len(channels)
+                                        : 0,
                                         7, mode, 4,
                                         8, idle, 4,
                                         9, fingerprint,
                                         fingerprint ? 20 : 0,
                                         10, umode_list ? umode_list->data :
-                                        NULL, umode_list ? umode_list->len :
+                                        NULL, umode_list ?
+                                        silc_buffer_len(umode_list) :
                                         0, 11, attrs, len);
 
          sent_reply = TRUE;
@@ -1539,7 +1571,7 @@ void silc_server_query_send_reply(SilcServer server,
        if (!entry->username) {
          silc_server_send_command_reply(server, cmd->sock, query->querycmd,
                                         status, 0, ident, 2,
-                                        2, idp->data, idp->len,
+                                        2, idp->data, silc_buffer_len(idp),
                                         3, nh, strlen(nh));
          sent_reply = TRUE;
        } else {
@@ -1549,13 +1581,14 @@ void silc_server_query_send_reply(SilcServer server,
          if (!strchr(entry->username, '@') && entry->connection) {
            hsock = entry->connection;
            silc_strncat(uh, sizeof(uh), "@", 1);
-           len = strlen(hsock->hostname);
-           silc_strncat(uh, sizeof(uh), hsock->hostname, len);
+           silc_socket_stream_get_info(hsock, NULL, (const char **)&tmp,
+                                       NULL, NULL);
+           silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
          }
 
          silc_server_send_command_reply(server, cmd->sock, query->querycmd,
                                         status, 0, ident, 3,
-                                        2, idp->data, idp->len,
+                                        2, idp->data, silc_buffer_len(idp),
                                         3, nh, strlen(nh),
                                         4, uh, strlen(uh));
          sent_reply = TRUE;
@@ -1571,7 +1604,7 @@ void silc_server_query_send_reply(SilcServer server,
        /* Send command reply */
        silc_server_send_command_reply(server, cmd->sock, query->querycmd,
                                       status, 0, ident, 4,
-                                      2, idp->data, idp->len,
+                                      2, idp->data, silc_buffer_len(idp),
                                       3, nh, strlen(nh),
                                       4, uh, strlen(uh),
                                       5, entry->userinfo,
@@ -1592,7 +1625,7 @@ void silc_server_query_send_reply(SilcServer server,
       /* Not one valid entry was found, send error.  If nickname was used
         in query send error based on that, otherwise the query->errors
         already includes proper errors. */
-      if (query->nickname || (!query->ids && query->attrs))
+      if (query->nickname[0] || (!query->ids && query->attrs))
        silc_server_query_add_error(server, query, 1, 1,
                                    SILC_STATUS_ERR_NO_SUCH_NICK);
 
@@ -1637,7 +1670,7 @@ void silc_server_query_send_reply(SilcServer server,
       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
                                     status, 0, ident, 2,
-                                    2, idp->data, idp->len,
+                                    2, idp->data, silc_buffer_len(idp),
                                     3, entry->server_name,
                                     entry->server_name ?
                                     strlen(entry->server_name) : 0);
@@ -1684,7 +1717,7 @@ void silc_server_query_send_reply(SilcServer server,
       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
                                     status, 0, ident, 2,
-                                    2, idp->data, idp->len,
+                                    2, idp->data, silc_buffer_len(idp),
                                     3, entry->channel_name,
                                     entry->channel_name ?
                                     strlen(entry->channel_name) : 0);
@@ -1726,14 +1759,14 @@ void silc_server_query_send_reply(SilcServer server,
          silc_id_payload_encode(query->ids[query->errors[i].index].id,
                                 query->ids[query->errors[k].index].id_type);
        tmp = idp->data;
-       len = idp->len;
+       len = silc_buffer_len(idp);
        type = 2;
       } else {
        /* Take added ID. */
        idp = silc_id_payload_encode(query->errors[i].id,
                                     query->errors[k].id_type);
        tmp = idp->data;
-       len = idp->len;
+       len = silc_buffer_len(idp);
        type = 2;
       }
 
@@ -1924,10 +1957,11 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server,
   /* Finally compute the digital signature of all the data we provided
      as an indication that we provided rightfull information, and this
      also authenticates our public key. */
-  if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1  &&
-      silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
-                              buffer->data, buffer->len,
-                              sign, &sign_len)) {
+  if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
+      sizeof(sign) -1  &&
+      silc_pkcs_sign(server->private_key, buffer->data,
+                    silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
+                    TRUE, server->sha1hash)) {
     pk.type = NULL;
     pk.data = sign;
     pk.data_len = sign_len;
@@ -1953,8 +1987,8 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server,
 
 SilcClientEntry silc_server_query_client(SilcServer server,
                                         const SilcClientID *client_id,
-                                        bool always_resolve,
-                                        bool *resolved)
+                                        SilcBool always_resolve,
+                                        SilcBool *resolved)
 {
   SilcClientEntry client;
 
@@ -1993,11 +2027,12 @@ SilcClientEntry silc_server_query_client(SilcServer server,
     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
                                            server->cmd_ident, 1,
-                                           4, idp->data, idp->len);
+                                           4, idp->data,
+                                           silc_buffer_len(idp));
     silc_server_packet_send(server, client ? client->router->connection :
                            SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, 0,
-                           buffer->data, buffer->len, FALSE);
+                           buffer->data, silc_buffer_len(buffer));
     silc_buffer_free(idp);
     silc_buffer_free(buffer);
 
index 523cf5ad0ddd223e5eb11878a2c63d59067b8519..53a11ee25fc86372e3df271861b958ab9349558f 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  server_query.h 
+  server_query.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
@@ -26,8 +26,8 @@
    SILC_COMMAND_IDENTIFY.  This function handles the reply sending
    to the entity who sent this query to us automatically.  Returns
    TRUE if the query is being processed or FALSE on error. */
-bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
-                              SilcServerCommandContext cmd);
+SilcBool silc_server_query_command(SilcServer server, SilcCommand querycmd,
+                                  SilcServerCommandContext cmd);
 
 /* Find client by the Client ID indicated by the `client_id', and if not
    found then query it by using WHOIS command.  The client information
@@ -40,7 +40,7 @@ bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
    function.  The server->cmd_ident includes the query identifier. */
 SilcClientEntry silc_server_query_client(SilcServer server,
                                         const SilcClientID *client_id,
-                                        bool always_resolve,
-                                        bool *resolved);
+                                        SilcBool always_resolve,
+                                        SilcBool *resolved);
 
 #endif /* SERVER_QUERY_H */
index 4fc8cacca2c1a4db6a4791b52885886ae57d0275..f7eb97b8d36298b6cbd600d1441e39903bd9614a 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -127,12 +127,12 @@ silc_server_remove_clients_channels(SilcServer server,
    too.  If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
    distributed to our local clients. */
 
-bool silc_server_remove_clients_by_server(SilcServer server,
-                                         SilcServerEntry router,
-                                         SilcServerEntry entry,
-                                         bool server_signoff)
+SilcBool silc_server_remove_clients_by_server(SilcServer server,
+                                             SilcServerEntry router,
+                                             SilcServerEntry entry,
+                                             SilcBool server_signoff)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry client = NULL;
   SilcBuffer idp;
@@ -165,145 +165,126 @@ bool silc_server_remove_clients_by_server(SilcServer server,
     argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
     argv_lens = silc_realloc(argv_lens,  sizeof(*argv_lens) * (argc + 1));
     argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
-    argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
-    memcpy(argv[argc], idp->data, idp->len);
-    argv_lens[argc] = idp->len;
+    argv[argc] = silc_calloc(silc_buffer_len(idp), sizeof(*argv[0]));
+    memcpy(argv[argc], idp->data, silc_buffer_len(idp));
+    argv_lens[argc] = silc_buffer_len(idp);
     argv_types[argc] = argc + 1;
     argc++;
     silc_buffer_free(idp);
   }
 
   if (silc_idcache_get_all(server->local_list->clients, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       client = (SilcClientEntry)id_cache->context;
-
-       /* If client is not registered, is not originated from `router'
-          and is not owned by `entry', skip it. */
-       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-           client->router != router ||
-           (router != entry && !SILC_ID_COMPARE(client->id, entry->id,
-                                                client->id->ip.data_len))) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
-
-       if (server_signoff) {
-         idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-         argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
-         argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
-                                  (argc + 1));
-         argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
-                                   (argc + 1));
-         argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
-         memcpy(argv[argc], idp->data, idp->len);
-         argv_lens[argc] = idp->len;
-         argv_types[argc] = argc + 1;
-         argc++;
-         silc_buffer_free(idp);
-       }
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      client = (SilcClientEntry)id_cache->context;
+
+      /* If client is not registered, is not originated from `router'
+        and is not owned by `entry', skip it. */
+      if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+         client->router != router ||
+         (router != entry && !SILC_ID_COMPARE(client->id, entry->id,
+                                              client->id->ip.data_len))) {
+       continue;
+      }
 
-       /* Update statistics */
-       server->stat.clients--;
-       if (server->stat.cell_clients)
-         server->stat.cell_clients--;
-       SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
-       SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
-
-       if (client->data.public_key)
-         silc_hash_table_del_by_context(server->pk_hash,
-                                        client->data.public_key,
-                                        client);
-       silc_server_remove_clients_channels(server, entry, clients,
-                                           client, channels);
-       silc_server_del_from_watcher_list(server, client);
-
-       /* Remove the client entry */
-       if (!server_signoff) {
-         client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-         client->mode = 0;
-         client->router = NULL;
-         client->connection = NULL;
-         id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-       } else {
-         silc_idlist_del_data(client);
-         silc_idlist_del_client(server->local_list, client);
-       }
+      if (server_signoff) {
+       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+       argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
+       argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
+                                (argc + 1));
+       argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
+                                 (argc + 1));
+       argv[argc] = silc_calloc(silc_buffer_len(idp), sizeof(*argv[0]));
+       memcpy(argv[argc], idp->data, silc_buffer_len(idp));
+       argv_lens[argc] = silc_buffer_len(idp);
+       argv_types[argc] = argc + 1;
+       argc++;
+       silc_buffer_free(idp);
+      }
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+      /* Update statistics */
+      server->stat.clients--;
+      if (server->stat.cell_clients)
+       server->stat.cell_clients--;
+      SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+      SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+      if (client->data.public_key)
+       silc_hash_table_del_by_context(server->pk_hash,
+                                      client->data.public_key,
+                                      client);
+      silc_server_remove_clients_channels(server, entry, clients,
+                                         client, channels);
+      silc_server_del_from_watcher_list(server, client);
+
+      /* Remove the client entry */
+      if (!server_signoff) {
+       client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+       client->mode = 0;
+       client->router = NULL;
+       client->connection = NULL;
+      } else {
+       silc_idlist_del_data(client);
+       silc_idlist_del_client(server->local_list, client);
       }
     }
-    silc_idcache_list_free(list);
   }
 
   if (silc_idcache_get_all(server->global_list->clients, &list)) {
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      client = (SilcClientEntry)id_cache->context;
+
+      /* If client is not registered, is not originated from `router'
+        and is not owned by `entry', skip it. */
+      if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+         client->router != router ||
+         (router != entry && !SILC_ID_COMPARE(client->id, entry->id,
+                                              client->id->ip.data_len))) {
+       continue;
+      }
 
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       client = (SilcClientEntry)id_cache->context;
-
-       /* If client is not registered, is not originated from `router'
-          and is not owned by `entry', skip it. */
-       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-           client->router != router ||
-           (router != entry && !SILC_ID_COMPARE(client->id, entry->id,
-                                                client->id->ip.data_len))) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
-
-       if (server_signoff) {
-         idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-         argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
-         argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
-                                  (argc + 1));
-         argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
-                                   (argc + 1));
-         argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
-         memcpy(argv[argc], idp->data, idp->len);
-         argv_lens[argc] = idp->len;
-         argv_types[argc] = argc + 1;
-         argc++;
-         silc_buffer_free(idp);
-       }
-
-       /* Update statistics */
-       server->stat.clients--;
-       if (server->stat.cell_clients)
-         server->stat.cell_clients--;
-       SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
-       SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
-
-       if (client->data.public_key)
-         silc_hash_table_del_by_context(server->pk_hash,
-                                        client->data.public_key,
-                                        client);
-       silc_server_remove_clients_channels(server, entry, clients,
-                                           client, channels);
-       silc_server_del_from_watcher_list(server, client);
-
-       /* Remove the client entry */
-       if (!server_signoff) {
-         client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-         client->mode = 0;
-         client->router = NULL;
-         client->connection = NULL;
-         id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-       } else {
-         silc_idlist_del_data(client);
-         silc_idlist_del_client(server->global_list, client);
-       }
+      if (server_signoff) {
+       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+       argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
+       argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
+                                (argc + 1));
+       argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
+                                 (argc + 1));
+       argv[argc] = silc_calloc(silc_buffer_len(idp), sizeof(*argv[0]));
+       memcpy(argv[argc], idp->data, silc_buffer_len(idp));
+       argv_lens[argc] = silc_buffer_len(idp);
+       argv_types[argc] = argc + 1;
+       argc++;
+       silc_buffer_free(idp);
+      }
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+      /* Update statistics */
+      server->stat.clients--;
+      if (server->stat.cell_clients)
+       server->stat.cell_clients--;
+      SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+      SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+      if (client->data.public_key)
+       silc_hash_table_del_by_context(server->pk_hash,
+                                      client->data.public_key,
+                                      client);
+      silc_server_remove_clients_channels(server, entry, clients,
+                                         client, channels);
+      silc_server_del_from_watcher_list(server, client);
+
+      /* Remove the client entry */
+      if (!server_signoff) {
+       client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+       client->mode = 0;
+       client->router = NULL;
+       client->connection = NULL;
+      } else {
+       silc_idlist_del_data(client);
+       silc_idlist_del_client(server->global_list, client);
       }
     }
-    silc_idcache_list_free(list);
   }
 
   /* Return now if we are shutting down */
@@ -347,11 +328,11 @@ bool silc_server_remove_clients_by_server(SilcServer server,
                                          argc, args);
     silc_server_packet_send_clients(server, clients,
                                    SILC_PACKET_NOTIFY, 0, FALSE,
-                                   not->data, not->len, FALSE);
+                                   not->data, silc_buffer_len(not));
 
     /* Send notify also to local backup routers */
     silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0,
-                           not->data, not->len, FALSE, TRUE);
+                           not->data, silc_buffer_len(not), FALSE, TRUE);
 
     silc_buffer_free(args);
     silc_buffer_free(not);
@@ -375,7 +356,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
     }
 
     /* Do not send the channel key if private channel key mode is set */
-    if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY || !channel->channel_key)
+    if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY || !channel->send_key)
       continue;
 
     silc_server_send_channel_key(server, NULL, channel,
@@ -393,122 +374,109 @@ silc_server_update_clients_by_real_server(SilcServer server,
                                          SilcServerEntry from,
                                          SilcServerEntry to,
                                          SilcClientEntry client,
-                                         bool local,
+                                         SilcBool local,
                                          SilcIDCacheEntry client_cache)
 {
   SilcServerEntry server_entry;
   SilcIDCacheEntry id_cache = NULL;
-  SilcIDCacheList list;
-  bool tolocal = (to == server->id_entry);
+  SilcList list;
+  SilcBool tolocal = (to == server->id_entry);
 
   SILC_LOG_DEBUG(("Start"));
 
   if (!silc_idcache_get_all(server->local_list->servers, &list))
     return NULL;
 
-  if (silc_idcache_list_first(list, &id_cache)) {
-    while (id_cache) {
-      server_entry = (SilcServerEntry)id_cache->context;
-      if (server_entry != from &&
-         (tolocal || server_entry != server->id_entry) &&
-         SILC_ID_COMPARE(server_entry->id, client->id,
-                         client->id->ip.data_len)) {
-       SILC_LOG_DEBUG(("Found (local) %s",
-                       silc_id_render(server_entry->id, SILC_ID_SERVER)));
-
-       if (!server_entry->data.send_key && server_entry->router) {
-         SILC_LOG_DEBUG(("Server not locally connected, use its router"));
-         /* If the client is not marked as local then move it to local list
-            since the server is local. */
-         if (!local) {
-           SILC_LOG_DEBUG(("Moving client to local list"));
-           silc_idcache_add(server->local_list->clients, client_cache->name,
-                            client_cache->id, client_cache->context,
-                            client_cache->expire, NULL);
-           silc_idcache_del_by_context(server->global_list->clients, client);
-         }
-         server_entry = server_entry->router;
-       } else {
-         SILC_LOG_DEBUG(("Server locally connected"));
-         /* If the client is not marked as local then move it to local list
-            since the server is local. */
-         if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
-           SILC_LOG_DEBUG(("Moving client to local list"));
-           silc_idcache_add(server->local_list->clients, client_cache->name,
-                            client_cache->id, client_cache->context,
-                            client_cache->expire, NULL);
-           silc_idcache_del_by_context(server->global_list->clients, client);
-
-         } else if (server->server_type == SILC_BACKUP_ROUTER && local) {
-           /* If we are backup router and this client is on local list, we
-              must move it to global list, as it is not currently local to
-              us (we are not primary). */
-           SILC_LOG_DEBUG(("Moving client to global list"));
-           silc_idcache_add(server->global_list->clients, client_cache->name,
-                            client_cache->id, client_cache->context,
-                            client_cache->expire, NULL);
-           silc_idcache_del_by_context(server->local_list->clients, client);
-         }
+  silc_list_start(list);
+  while ((id_cache = silc_list_get(list))) {
+    server_entry = (SilcServerEntry)id_cache->context;
+    if (server_entry != from &&
+       (tolocal || server_entry != server->id_entry) &&
+       SILC_ID_COMPARE(server_entry->id, client->id,
+                       client->id->ip.data_len)) {
+      SILC_LOG_DEBUG(("Found (local) %s",
+                     silc_id_render(server_entry->id, SILC_ID_SERVER)));
+
+      if (!SILC_IS_LOCAL(server_entry) && server_entry->router) {
+       SILC_LOG_DEBUG(("Server not locally connected, use its router"));
+       /* If the client is not marked as local then move it to local list
+          since the server is local. */
+       if (!local) {
+         SILC_LOG_DEBUG(("Moving client to local list"));
+         silc_idcache_add(server->local_list->clients, client_cache->name,
+                          client_cache->id, client_cache->context);
+         silc_idcache_del_by_context(server->global_list->clients, client,
+                                     NULL);
+       }
+       server_entry = server_entry->router;
+      } else {
+       SILC_LOG_DEBUG(("Server locally connected"));
+       /* If the client is not marked as local then move it to local list
+          since the server is local. */
+       if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
+         SILC_LOG_DEBUG(("Moving client to local list"));
+         silc_idcache_add(server->local_list->clients, client_cache->name,
+                          client_cache->id, client_cache->context);
+         silc_idcache_del_by_context(server->global_list->clients, client,
+                                     NULL);
+
+       } else if (server->server_type == SILC_BACKUP_ROUTER && local) {
+         /* If we are backup router and this client is on local list, we
+            must move it to global list, as it is not currently local to
+            us (we are not primary). */
+         SILC_LOG_DEBUG(("Moving client to global list"));
+         silc_idcache_add(server->global_list->clients, client_cache->name,
+                          client_cache->id, client_cache->context);
+         silc_idcache_del_by_context(server->local_list->clients, client,
+                                     NULL);
        }
-
-       silc_idcache_list_free(list);
-       return server_entry;
       }
 
-      if (!silc_idcache_list_next(list, &id_cache))
-       break;
+      return server_entry;
     }
   }
 
-  silc_idcache_list_free(list);
-
   if (!silc_idcache_get_all(server->global_list->servers, &list))
     return NULL;
 
-  if (silc_idcache_list_first(list, &id_cache)) {
-    while (id_cache) {
-      server_entry = (SilcServerEntry)id_cache->context;
-      if (server_entry != from && server_entry != server->id_entry &&
-         (tolocal || server_entry != server->id_entry) &&
-         SILC_ID_COMPARE(server_entry->id, client->id,
-                         client->id->ip.data_len)) {
-       SILC_LOG_DEBUG(("Found (global) %s",
-                       silc_id_render(server_entry->id, SILC_ID_SERVER)));
-
-       if (!server_entry->data.send_key && server_entry->router) {
-         SILC_LOG_DEBUG(("Server not locally connected, use its router"));
-         /* If the client is marked as local then move it to global list
-            since the server is global. */
-         if (local) {
-           SILC_LOG_DEBUG(("Moving client to global list"));
-           silc_idcache_add(server->global_list->clients, client_cache->name,
-                            client_cache->id, client_cache->context, 0, NULL);
-           silc_idcache_del_by_context(server->local_list->clients, client);
-         }
-         server_entry = server_entry->router;
-       } else {
-         SILC_LOG_DEBUG(("Server locally connected"));
-         /* If the client is marked as local then move it to global list
-            since the server is global. */
-         if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
-           SILC_LOG_DEBUG(("Moving client to global list"));
-           silc_idcache_add(server->global_list->clients, client_cache->name,
-                            client_cache->id, client_cache->context, 0, NULL);
-           silc_idcache_del_by_context(server->local_list->clients, client);
-         }
+  silc_list_start(list);
+  while ((id_cache = silc_list_get(list))) {
+    server_entry = (SilcServerEntry)id_cache->context;
+    if (server_entry != from && server_entry != server->id_entry &&
+       (tolocal || server_entry != server->id_entry) &&
+       SILC_ID_COMPARE(server_entry->id, client->id,
+                       client->id->ip.data_len)) {
+      SILC_LOG_DEBUG(("Found (global) %s",
+                     silc_id_render(server_entry->id, SILC_ID_SERVER)));
+
+      if (!SILC_IS_LOCAL(server_entry) && server_entry->router) {
+       SILC_LOG_DEBUG(("Server not locally connected, use its router"));
+       /* If the client is marked as local then move it to global list
+          since the server is global. */
+       if (local) {
+         SILC_LOG_DEBUG(("Moving client to global list"));
+         silc_idcache_add(server->global_list->clients, client_cache->name,
+                          client_cache->id, client_cache->context);
+         silc_idcache_del_by_context(server->local_list->clients, client,
+                                     NULL);
+       }
+       server_entry = server_entry->router;
+      } else {
+       SILC_LOG_DEBUG(("Server locally connected"));
+       /* If the client is marked as local then move it to global list
+          since the server is global. */
+       if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
+         SILC_LOG_DEBUG(("Moving client to global list"));
+         silc_idcache_add(server->global_list->clients, client_cache->name,
+                          client_cache->id, client_cache->context);
+         silc_idcache_del_by_context(server->local_list->clients, client,
+                                     NULL);
        }
-
-       silc_idcache_list_free(list);
-       return server_entry;
       }
-
-      if (!silc_idcache_list_next(list, &id_cache))
-       break;
+      return server_entry;
     }
   }
 
-  silc_idcache_list_free(list);
-
   return NULL;
 }
 
@@ -522,12 +490,12 @@ silc_server_update_clients_by_real_server(SilcServer server,
 void silc_server_update_clients_by_server(SilcServer server,
                                          SilcServerEntry from,
                                          SilcServerEntry to,
-                                         bool resolve_real_server)
+                                         SilcBool resolve_real_server)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry client = NULL;
-  bool local;
+  SilcBool local;
 
   if (from && from->id) {
     SILC_LOG_DEBUG(("Changing from server %s",
@@ -541,123 +509,105 @@ void silc_server_update_clients_by_server(SilcServer server,
   SILC_LOG_DEBUG(("global list"));
   local = FALSE;
   if (silc_idcache_get_all(server->global_list->clients, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       client = (SilcClientEntry)id_cache->context;
-
-       /* If entry is disabled skip it.  If entry is local to us, do not
-          switch it to anyone else, it is ours so skip it. */
-       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-           SILC_IS_LOCAL(client)) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
-
-       SILC_LOG_DEBUG(("Client %s",
-                       silc_id_render(client->id, SILC_ID_CLIENT)));
-       if (client->router && client->router->id)
-         SILC_LOG_DEBUG(("Client->router %s",
-                         silc_id_render(client->router->id, SILC_ID_SERVER)));
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      client = (SilcClientEntry)id_cache->context;
+
+      /* If entry is disabled skip it.  If entry is local to us, do not
+        switch it to anyone else, it is ours so skip it. */
+      if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+         SILC_IS_LOCAL(client))
+       continue;
 
-       if (from) {
-         if (client->router == from) {
-           if (resolve_real_server) {
-             client->router =
-               silc_server_update_clients_by_real_server(server, from, to,
-                                                         client, local,
-                                                         id_cache);
-             if (!client->router) {
-               if (server->server_type == SILC_ROUTER)
-                 client->router = from;
-               else
-                 client->router = to;
-             }
-           } else {
-             client->router = to;
+      SILC_LOG_DEBUG(("Client %s",
+                     silc_id_render(client->id, SILC_ID_CLIENT)));
+      if (client->router && client->router->id)
+       SILC_LOG_DEBUG(("Client->router %s",
+                       silc_id_render(client->router->id, SILC_ID_SERVER)));
+
+      if (from) {
+       if (client->router == from) {
+         if (resolve_real_server) {
+           client->router =
+             silc_server_update_clients_by_real_server(server, from, to,
+                                                       client, local,
+                                                       id_cache);
+           if (!client->router) {
+             if (server->server_type == SILC_ROUTER)
+               client->router = from;
+             else
+               client->router = to;
            }
+         } else {
+           client->router = to;
          }
-       } else {
-         /* All are changed */
-         if (resolve_real_server)
-           /* Call this so that the entry is moved to correct list if
-              needed.  No resolving by real server is actually done. */
-           silc_server_update_clients_by_real_server(server, NULL, to,
-                                                     client, local,
-                                                     id_cache);
-
-         client->router = to;
        }
-
-       if (client->router && client->router->id)
-         SILC_LOG_DEBUG(("Client changed to %s",
-                         silc_id_render(client->router->id, SILC_ID_SERVER)));
-
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+      } else {
+       /* All are changed */
+       if (resolve_real_server)
+         /* Call this so that the entry is moved to correct list if
+            needed.  No resolving by real server is actually done. */
+         silc_server_update_clients_by_real_server(server, NULL, to,
+                                                   client, local,
+                                                   id_cache);
+
+       client->router = to;
       }
+
+      if (client->router && client->router->id)
+       SILC_LOG_DEBUG(("Client changed to %s",
+                       silc_id_render(client->router->id, SILC_ID_SERVER)));
     }
-    silc_idcache_list_free(list);
   }
 
   SILC_LOG_DEBUG(("local list"));
   local = TRUE;
   if (silc_idcache_get_all(server->local_list->clients, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       client = (SilcClientEntry)id_cache->context;
-
-       /* If entry is disabled skip it.  If entry is local to us, do not
-          switch it to anyone else, it is ours so skip it. */
-       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-           SILC_IS_LOCAL(client)) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
-
-       SILC_LOG_DEBUG(("Client %s",
-                       silc_id_render(client->id, SILC_ID_CLIENT)));
-       if (client->router && client->router->id)
-         SILC_LOG_DEBUG(("Client->router %s",
-                         silc_id_render(client->router->id, SILC_ID_SERVER)));
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      client = (SilcClientEntry)id_cache->context;
+
+      /* If entry is disabled skip it.  If entry is local to us, do not
+        switch it to anyone else, it is ours so skip it. */
+      if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+         SILC_IS_LOCAL(client))
+       continue;
 
-       if (from) {
-         if (client->router == from) {
-           if (resolve_real_server) {
-             client->router =
-               silc_server_update_clients_by_real_server(server, from, to,
-                                                         client, local,
-                                                         id_cache);
-             if (!client->router)
-               client->router = from;
-           } else {
-             client->router = to;
-           }
+      SILC_LOG_DEBUG(("Client %s",
+                     silc_id_render(client->id, SILC_ID_CLIENT)));
+      if (client->router && client->router->id)
+       SILC_LOG_DEBUG(("Client->router %s",
+                       silc_id_render(client->router->id, SILC_ID_SERVER)));
+
+      if (from) {
+       if (client->router == from) {
+         if (resolve_real_server) {
+           client->router =
+             silc_server_update_clients_by_real_server(server, from, to,
+                                                       client, local,
+                                                       id_cache);
+           if (!client->router)
+             client->router = from;
+         } else {
+           client->router = to;
          }
-       } else {
-         /* All are changed */
-         if (resolve_real_server)
-           /* Call this so that the entry is moved to correct list if
-              needed.  No resolving by real server is actually done. */
-           silc_server_update_clients_by_real_server(server, NULL, to,
-                                                     client, local,
-                                                     id_cache);
-
-         client->router = to;
        }
-
-       if (client->router && client->router->id)
-         SILC_LOG_DEBUG(("Client changed to %s",
-                         silc_id_render(client->router->id, SILC_ID_SERVER)));
-
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+      } else {
+       /* All are changed */
+       if (resolve_real_server)
+         /* Call this so that the entry is moved to correct list if
+            needed.  No resolving by real server is actually done. */
+         silc_server_update_clients_by_real_server(server, NULL, to,
+                                                   client, local,
+                                                   id_cache);
+
+       client->router = to;
       }
+
+      if (client->router && client->router->id)
+       SILC_LOG_DEBUG(("Client changed to %s",
+                       silc_id_render(client->router->id, SILC_ID_SERVER)));
     }
-    silc_idcache_list_free(list);
   }
 }
 
@@ -668,120 +618,102 @@ void silc_server_update_servers_by_server(SilcServer server,
                                          SilcServerEntry from,
                                          SilcServerEntry to)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server_entry = NULL;
 
   SILC_LOG_DEBUG(("Updating servers"));
 
   if (silc_idcache_get_all(server->local_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-
-       /* If entry is local to us, do not switch it to any anyone else,
-          it is ours. */
-       if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
-           server_entry == from) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      server_entry = (SilcServerEntry)id_cache->context;
 
-       /* If we are standalone router, any server that is not directly
-          connected to cannot exist anymore.  If we are not standalone
-          we update it correctly. */
-       if (server->server_type == SILC_ROUTER && server->standalone) {
-         silc_server_backup_del(server, server_entry);
-         silc_server_backup_replaced_del(server, server_entry);
-         silc_idlist_del_data(server_entry);
-         silc_idlist_del_server(server->local_list, server_entry);
-         server->stat.servers--;
-         server->stat.cell_servers--;
-       } else {
-         /* XXX if we are not standalone, do a check from local config
-            whether this server is in our cell, but not connected to
-            us (in which case we must remove it). */
-
-         if (from) {
-           if (server_entry->router == from) {
-             SILC_LOG_DEBUG(("Updating server (local) %s",
-                             server_entry->server_name ?
-                             server_entry->server_name : ""));
-             server_entry->router = to;
-             server_entry->connection = to->connection;
-           }
-         } else {
-           /* Update all */
+      /* If entry is local to us, do not switch it to any anyone else,
+        it is ours. */
+      if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
+         server_entry == from)
+       continue;
+
+      /* If we are standalone router, any server that is not directly
+        connected to cannot exist anymore.  If we are not standalone
+        we update it correctly. */
+      if (server->server_type == SILC_ROUTER && server->standalone) {
+       silc_server_backup_del(server, server_entry);
+       silc_server_backup_replaced_del(server, server_entry);
+       silc_idlist_del_data(server_entry);
+       silc_idlist_del_server(server->local_list, server_entry);
+       server->stat.servers--;
+       server->stat.cell_servers--;
+      } else {
+       /* XXX if we are not standalone, do a check from local config
+          whether this server is in our cell, but not connected to
+          us (in which case we must remove it). */
+
+       if (from) {
+         if (server_entry->router == from) {
            SILC_LOG_DEBUG(("Updating server (local) %s",
                            server_entry->server_name ?
                            server_entry->server_name : ""));
            server_entry->router = to;
            server_entry->connection = to->connection;
          }
+       } else {
+         /* Update all */
+         SILC_LOG_DEBUG(("Updating server (local) %s",
+                         server_entry->server_name ?
+                         server_entry->server_name : ""));
+         server_entry->router = to;
+         server_entry->connection = to->connection;
        }
-
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
       }
     }
-    silc_idcache_list_free(list);
   }
 
   if (silc_idcache_get_all(server->global_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-
-       /* If entry is local to us, do not switch it to anyone else,
-          it is ours. */
-       if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
-           server_entry == from) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      server_entry = (SilcServerEntry)id_cache->context;
 
-       /* If we are standalone router, any server that is not directly
-          connected to cannot exist anymore.  If we are not standalone
-          we update it correctly. */
-       if (server->server_type == SILC_ROUTER && server->standalone) {
-         silc_server_backup_del(server, server_entry);
-         silc_server_backup_replaced_del(server, server_entry);
-         silc_idlist_del_data(server_entry);
-         silc_idlist_del_server(server->global_list, server_entry);
-         server->stat.servers--;
-         server->stat.cell_servers--;
-       } else {
-         /* XXX if we are not standalone, do a check from local config
-            whether this server is in our cell, but not connected to
-            us (in which case we must remove it). */
-
-         if (from) {
-           if (server_entry->router == from) {
-             SILC_LOG_DEBUG(("Updating server (global) %s",
-                             server_entry->server_name ?
-                             server_entry->server_name : ""));
-             server_entry->router = to;
-             server_entry->connection = to->connection;
-           }
-         } else {
-           /* Update all */
+      /* If entry is local to us, do not switch it to anyone else,
+        it is ours. */
+      if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
+         server_entry == from)
+       continue;
+
+      /* If we are standalone router, any server that is not directly
+        connected to cannot exist anymore.  If we are not standalone
+        we update it correctly. */
+      if (server->server_type == SILC_ROUTER && server->standalone) {
+       silc_server_backup_del(server, server_entry);
+       silc_server_backup_replaced_del(server, server_entry);
+       silc_idlist_del_data(server_entry);
+       silc_idlist_del_server(server->global_list, server_entry);
+       server->stat.servers--;
+       server->stat.cell_servers--;
+      } else {
+       /* XXX if we are not standalone, do a check from local config
+          whether this server is in our cell, but not connected to
+          us (in which case we must remove it). */
+
+       if (from) {
+         if (server_entry->router == from) {
            SILC_LOG_DEBUG(("Updating server (global) %s",
                            server_entry->server_name ?
                            server_entry->server_name : ""));
            server_entry->router = to;
            server_entry->connection = to->connection;
          }
+       } else {
+         /* Update all */
+         SILC_LOG_DEBUG(("Updating server (global) %s",
+                         server_entry->server_name ?
+                         server_entry->server_name : ""));
+         server_entry->router = to;
+         server_entry->connection = to->connection;
        }
-
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
       }
     }
-    silc_idcache_list_free(list);
   }
 }
 
@@ -791,56 +723,40 @@ void silc_server_update_servers_by_server(SilcServer server,
    dropped if `toggle_enabled' is FALSE, after this function is called. */
 
 void silc_server_local_servers_toggle_enabled(SilcServer server,
-                                             bool toggle_enabled)
+                                             SilcBool toggle_enabled)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server_entry = NULL;
 
   if (silc_idcache_get_all(server->local_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-       if (!SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      server_entry = (SilcServerEntry)id_cache->context;
+      if (!SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry)
+       continue;
 
-       if (toggle_enabled)
-         server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
-       else
-         server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
+      if (toggle_enabled)
+       server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+      else
+       server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
-      }
     }
-    silc_idcache_list_free(list);
   }
 
   if (silc_idcache_get_all(server->global_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-       if (!SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      server_entry = (SilcServerEntry)id_cache->context;
+      if (!SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry)
+       continue;
 
-       if (toggle_enabled)
-         server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
-       else
-         server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
+      if (toggle_enabled)
+       server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+      else
+       server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
-      }
     }
-    silc_idcache_list_free(list);
   }
 }
 
@@ -852,9 +768,9 @@ void silc_server_local_servers_toggle_enabled(SilcServer server,
 
 void silc_server_remove_servers_by_server(SilcServer server,
                                          SilcServerEntry from,
-                                         bool remove_clients)
+                                         SilcBool remove_clients)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server_entry = NULL;
 
@@ -862,59 +778,41 @@ void silc_server_remove_servers_by_server(SilcServer server,
                  from->server_name ? from->server_name : "server"));
 
   if (silc_idcache_get_all(server->local_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-       if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
-         server_entry->router != from || server_entry == from) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
-
-       /* Remove clients owned by this server */
-       if (remove_clients)
-         silc_server_remove_clients_by_server(server, from, server_entry,
-                                              TRUE);
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      server_entry = (SilcServerEntry)id_cache->context;
+      if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
+         server_entry->router != from || server_entry == from)
+       continue;
 
-       /* Remove the server */
-       silc_server_backup_del(server, server_entry);
-       silc_idlist_del_server(server->local_list, server_entry);
+      /* Remove clients owned by this server */
+      if (remove_clients)
+       silc_server_remove_clients_by_server(server, from, server_entry,
+                                            TRUE);
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
-      }
+      /* Remove the server */
+      silc_server_backup_del(server, server_entry);
+      silc_idlist_del_server(server->local_list, server_entry);
     }
-    silc_idcache_list_free(list);
   }
 
   if (silc_idcache_get_all(server->global_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-       if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
-         server_entry->router != from || server_entry == from) {
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
-         else
-           continue;
-       }
-
-       /* Remove clients owned by this server */
-       if (remove_clients)
-         silc_server_remove_clients_by_server(server, from, server_entry,
-                                              TRUE);
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      server_entry = (SilcServerEntry)id_cache->context;
+      if (SILC_IS_LOCAL(server_entry) || server_entry == server->id_entry ||
+         server_entry->router != from || server_entry == from)
+       continue;
 
-       /* Remove the server */
-       silc_server_backup_del(server, server_entry);
-       silc_idlist_del_server(server->global_list, server_entry);
+      /* Remove clients owned by this server */
+      if (remove_clients)
+       silc_server_remove_clients_by_server(server, from, server_entry,
+                                            TRUE);
 
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
-      }
+      /* Remove the server */
+      silc_server_backup_del(server, server_entry);
+      silc_idlist_del_server(server->global_list, server_entry);
     }
-    silc_idcache_list_free(list);
   }
 }
 
@@ -923,23 +821,19 @@ void silc_server_remove_servers_by_server(SilcServer server,
 void silc_server_remove_channels_by_server(SilcServer server,
                                           SilcServerEntry from)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel = NULL;
 
   SILC_LOG_DEBUG(("Removing channels by server"));
 
   if (silc_idcache_get_all(server->global_list->channels, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       channel = (SilcChannelEntry)id_cache->context;
-       if (channel->router == from)
-         silc_idlist_del_channel(server->global_list, channel);
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
-      }
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      channel = (SilcChannelEntry)id_cache->context;
+      if (channel->router == from)
+       silc_idlist_del_channel(server->global_list, channel);
     }
-    silc_idcache_list_free(list);
   }
 }
 
@@ -949,35 +843,31 @@ void silc_server_update_channels_by_server(SilcServer server,
                                           SilcServerEntry from,
                                           SilcServerEntry to)
 {
-  SilcIDCacheList list = NULL;
+  SilcList list;
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel = NULL;
 
   SILC_LOG_DEBUG(("Updating channels by server"));
 
   if (silc_idcache_get_all(server->global_list->channels, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       channel = (SilcChannelEntry)id_cache->context;
-       if (from) {
-         if (channel->router == from)
-           channel->router = to;
-       } else {
-         /* Update all */
+    silc_list_start(list);
+    while ((id_cache = silc_list_get(list))) {
+      channel = (SilcChannelEntry)id_cache->context;
+      if (from) {
+       if (channel->router == from)
          channel->router = to;
-       }
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+      } else {
+       /* Update all */
+       channel->router = to;
       }
     }
-    silc_idcache_list_free(list);
   }
 }
 
 /* Checks whether given channel has global users.  If it does this returns
    TRUE and FALSE if there is only locally connected clients on the channel. */
 
-bool silc_server_channel_has_global(SilcChannelEntry channel)
+SilcBool silc_server_channel_has_global(SilcChannelEntry channel)
 {
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
@@ -997,7 +887,7 @@ bool silc_server_channel_has_global(SilcChannelEntry channel)
 /* Checks whether given channel has locally connected users.  If it does this
    returns TRUE and FALSE if there is not one locally connected client. */
 
-bool silc_server_channel_has_local(SilcChannelEntry channel)
+SilcBool silc_server_channel_has_local(SilcChannelEntry channel)
 {
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
@@ -1019,12 +909,12 @@ bool silc_server_channel_has_local(SilcChannelEntry channel)
    users are removed from the channel.  Returns TRUE if the channel is
    destroyed totally, and FALSE if it is permanent and remains. */
 
-bool silc_server_channel_delete(SilcServer server,
-                               SilcChannelEntry channel)
+SilcBool silc_server_channel_delete(SilcServer server,
+                                   SilcChannelEntry channel)
 {
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
-  bool delchan = !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH);
+  SilcBool delchan = !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH);
 
   SILC_LOG_DEBUG(("Deleting channel %s", channel->channel_name));
 
@@ -1082,9 +972,9 @@ bool silc_server_channel_delete(SilcServer server,
    always in up to date thus we can only check the channel list from
    `client' which is faster than checking the user list from `channel'. */
 
-bool silc_server_client_on_channel(SilcClientEntry client,
-                                  SilcChannelEntry channel,
-                                  SilcChannelClientEntry *chl)
+SilcBool silc_server_client_on_channel(SilcClientEntry client,
+                                      SilcChannelEntry channel,
+                                      SilcChannelClientEntry *chl)
 {
   if (!client || !channel)
     return FALSE;
@@ -1094,24 +984,57 @@ bool silc_server_client_on_channel(SilcClientEntry client,
 }
 
 /* Find number of sockets by IP address indicated by `ip'. Returns 0 if
-   socket connections with the IP address does not exist. */
+   socket connections with the IP address does not exist.  Counts only
+   fully established connections. */
 
 SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
-                                        SilcSocketType type)
+                                        SilcConnectionType type)
 {
-  int i, count;
-
-  for (i = 0, count = 0; i < server->config->param.connections_max; i++) {
-    if (server->sockets[i] && !SILC_IS_LISTENER(server->sockets[i]) &&
-       !SILC_IS_HOST_LOOKUP(server->sockets[i]) &&
-       !strcmp(server->sockets[i]->ip, ip) &&
-       server->sockets[i]->type == type)
+  SilcServerConnection conn;
+  SilcIDListData idata;
+  const char *ipaddr;
+  int count = 0;
+
+  silc_dlist_start(server->conns);
+  while ((conn = silc_dlist_get(server->conns))) {
+    if (!conn->sock)
+      continue;
+    silc_socket_stream_get_info(conn->sock, NULL, NULL, &ipaddr, NULL);
+    idata = silc_packet_get_context(conn->sock);
+    if (!strcmp(ipaddr, ip) && idata && idata->conn_type == type)
       count++;
   }
 
   return count;
 }
 
+/* Find active socket connection by the IP address and port indicated by
+   `ip' and `port', and socket connection type of `type'. */
+
+SilcPacketStream
+silc_server_find_socket_by_host(SilcServer server,
+                               SilcConnectionType type,
+                               const char *ip, SilcUInt16 port)
+{
+  SilcServerConnection conn;
+  SilcIDListData idata;
+  const char *ipaddr;
+
+  silc_dlist_start(server->conns);
+  while ((conn = silc_dlist_get(server->conns))) {
+    if (!conn->sock)
+      continue;
+    idata = silc_packet_get_context(conn->sock);
+    silc_socket_stream_get_info(conn->sock, NULL, NULL, &ipaddr, NULL);
+    if (!strcmp(ipaddr, ip) &&
+       (!port || conn->remote_port == port) &&
+       idata->conn_type == type)
+      return conn->sock;
+  }
+
+  return NULL;
+}
+
 /* Find number of sockets by IP address indicated by remote host, indicatd
    by `ip' or `hostname', `port', and `type'.  Returns 0 if socket connections
    does not exist. If `ip' is provided then `hostname' is ignored. */
@@ -1119,99 +1042,91 @@ SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
 SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
                                             const char *ip,
                                             const char *hostname,
-                                            SilcUInt16 port,
-                                            SilcSocketType type)
+                                            SilcUInt16 port)
 {
-  int i, count;
+  SilcServerConnection conn;
+  int count = 0;
 
   if (!ip && !hostname)
     return 0;
 
-  for (i = 0, count = 0; i < server->config->param.connections_max; i++) {
-    if (server->sockets[i] && !SILC_IS_LISTENER(server->sockets[i]) &&
-       !SILC_IS_HOST_LOOKUP(server->sockets[i]) &&
-       ((ip && !strcmp(server->sockets[i]->ip, ip)) ||
-        (hostname && !strcmp(server->sockets[i]->hostname, hostname))) &&
-       server->sockets[i]->port == port &&
-       server->sockets[i]->type == type)
+  silc_dlist_start(server->conns);
+  while ((conn = silc_dlist_get(server->conns))) {
+    if (((ip && !strcmp(conn->remote_host, ip)) ||
+        (hostname && !strcmp(conn->remote_host, hostname))) &&
+       conn->remote_port == port)
       count++;
   }
 
   return count;
 }
 
-/* Finds locally cached public key by the public key received in the SKE.
-   If we have it locally cached then we trust it and will use it in the
-   authentication protocol.  Returns the locally cached public key or NULL
-   if we do not find the public key.  */
+/* SKR find callbcak */
 
-SilcPublicKey silc_server_find_public_key(SilcServer server,
-                                         SilcHashTable local_public_keys,
-                                         SilcPublicKey remote_public_key)
+static void find_callback(SilcSKR skr, SilcSKRFind find,
+                         SilcSKRStatus status, SilcDList keys,
+                         void *context)
 {
-  SilcPublicKey cached_key;
-
-  SILC_LOG_DEBUG(("Find remote public key (%d keys in local cache)",
-                 silc_hash_table_count(local_public_keys)));
-
-  if (!silc_hash_table_find_ext(local_public_keys, remote_public_key,
-                               (void *)&cached_key, NULL,
-                               silc_hash_public_key, NULL,
-                               silc_hash_public_key_compare, NULL)) {
-    SILC_LOG_ERROR(("Public key not found"));
-    return NULL;
+  SilcPublicKey *public_key = context;
+  SilcSKRKey key;
+
+  if (keys) {
+    silc_dlist_start(keys);
+    key = silc_dlist_get(keys);
+    *public_key = key->key;
+    silc_dlist_uninit(keys);
   }
 
-  SILC_LOG_DEBUG(("Found public key"));
-
-  return cached_key;
+  silc_skr_find_free(find);
 }
 
-/* This returns the first public key from the table of public keys.  This
-   is used only in cases where single public key exists in the table and
-   we want to get a pointer to it.  For public key tables that has multiple
-   keys in it the silc_server_find_public_key must be used. */
+/* Get public key. For public key tables that has multiple keys in it the
+   silc_server_find_public_key must be used. */
 
 SilcPublicKey silc_server_get_public_key(SilcServer server,
-                                        SilcHashTable local_public_keys)
+                                        SilcSKRKeyUsage usage,
+                                        void *key_context)
 {
-  SilcPublicKey cached_key;
-  SilcHashTableList htl;
+  SilcSKRFind find;
+  SilcPublicKey public_key = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
-  assert(silc_hash_table_count(local_public_keys) < 2);
-
-  silc_hash_table_list(local_public_keys, &htl);
-  if (!silc_hash_table_get(&htl, NULL, (void *)&cached_key)) {
-    silc_hash_table_list_reset(&htl);
+  find = silc_skr_find_alloc();
+  if (!find)
     return NULL;
-  }
-  silc_hash_table_list_reset(&htl);
 
-  return cached_key;
+  silc_skr_find_set_usage(find, usage);
+  silc_skr_find_set_context(find, key_context);
+  silc_skr_find(server->repository, server->schedule,
+               find, find_callback, &public_key);
+
+  return public_key;
 }
 
 /* Check whether the connection `sock' is allowed to connect to us.  This
    checks for example whether there is too much connections for this host,
    and required version for the host etc. */
 
-bool silc_server_connection_allowed(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   SilcSocketType type,
-                                   SilcServerConfigConnParams *global,
-                                   SilcServerConfigConnParams *params,
-                                   SilcSKE ske)
+SilcBool silc_server_connection_allowed(SilcServer server,
+                                       SilcPacketStream sock,
+                                       SilcConnectionType type,
+                                       SilcServerConfigConnParams *global,
+                                       SilcServerConfigConnParams *params,
+                                       SilcSKE ske)
 {
-  SilcUInt32 conn_number = (type == SILC_SOCKET_TYPE_CLIENT ?
+  SilcUInt32 conn_number = (type == SILC_CONN_CLIENT ?
                            server->stat.my_clients :
-                           type == SILC_SOCKET_TYPE_SERVER ?
+                           type == SILC_CONN_SERVER ?
                            server->stat.my_servers :
                            server->stat.my_routers);
   SilcUInt32 num_sockets, max_hosts, max_per_host;
   SilcUInt32 r_protocol_version, l_protocol_version;
   SilcUInt32 r_software_version, l_software_version;
   char *r_vendor_version = NULL, *l_vendor_version;
+  const char *hostname, *ip;
+
+  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
 
   SILC_LOG_DEBUG(("Checking whether connection is allowed"));
 
@@ -1232,14 +1147,11 @@ bool silc_server_connection_allowed(SilcServer server,
   if (ske && silc_ske_parse_version(ske, &r_protocol_version, NULL,
                                    &r_software_version, NULL,
                                    &r_vendor_version)) {
-    sock->version = r_protocol_version;
-
     /* Match protocol version */
     if (l_protocol_version && r_protocol_version &&
        r_protocol_version < l_protocol_version) {
       SILC_LOG_INFO(("Connection %s (%s) is too old version",
-                    sock->hostname, sock->ip));
-      sock->protocol = NULL;
+                    hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_VERSION,
                                    "You support too old protocol version");
@@ -1250,8 +1162,7 @@ bool silc_server_connection_allowed(SilcServer server,
     if (l_software_version && r_software_version &&
        r_software_version < l_software_version) {
       SILC_LOG_INFO(("Connection %s (%s) is too old version",
-                    sock->hostname, sock->ip));
-      sock->protocol = NULL;
+                    hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_VERSION,
                                    "You support too old software version");
@@ -1262,8 +1173,7 @@ bool silc_server_connection_allowed(SilcServer server,
     if (l_vendor_version && r_vendor_version &&
        !silc_string_match(l_vendor_version, r_vendor_version)) {
       SILC_LOG_INFO(("Connection %s (%s) is unsupported version",
-                    sock->hostname, sock->ip));
-      sock->protocol = NULL;
+                    hostname, ip));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_VERSION,
                                    "Your software is not supported");
@@ -1274,15 +1184,14 @@ bool silc_server_connection_allowed(SilcServer server,
 
   /* Check for maximum connections limit */
 
-  num_sockets = silc_server_num_sockets_by_ip(server, sock->ip, type);
+  num_sockets = silc_server_num_sockets_by_ip(server, ip, type);
   max_hosts = (params ? params->connections_max : global->connections_max);
   max_per_host = (params ? params->connections_max_per_host :
                  global->connections_max_per_host);
 
   if (max_hosts && conn_number >= max_hosts) {
     SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
-                  sock->hostname, sock->ip));
-    sock->protocol = NULL;
+                  hostname, ip));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_RESOURCE_LIMIT,
                                  "Server is full, try again later");
@@ -1291,8 +1200,7 @@ bool silc_server_connection_allowed(SilcServer server,
 
   if (num_sockets >= max_per_host) {
     SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
-                  sock->hostname, sock->ip));
-    sock->protocol = NULL;
+                  hostname, ip));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_RESOURCE_LIMIT,
                                  "Too many connections from your host");
@@ -1305,13 +1213,13 @@ bool silc_server_connection_allowed(SilcServer server,
 /* Checks that client has rights to add or remove channel modes. If any
    of the checks fails FALSE is returned. */
 
-bool silc_server_check_cmode_rights(SilcServer server,
+SilcBool silc_server_check_cmode_rights(SilcServer server,
                                    SilcChannelEntry channel,
                                    SilcChannelClientEntry client,
                                    SilcUInt32 mode)
 {
-  bool is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
-  bool is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
+  SilcBool is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
+  SilcBool is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
 
   /* Check whether has rights to change anything */
   if (!is_op && !is_fo)
@@ -1417,11 +1325,11 @@ bool silc_server_check_cmode_rights(SilcServer server,
 /* Check that the client has rights to change its user mode.  Returns
    FALSE if setting some mode is not allowed. */
 
-bool silc_server_check_umode_rights(SilcServer server,
+SilcBool silc_server_check_umode_rights(SilcServer server,
                                    SilcClientEntry client,
                                    SilcUInt32 mode)
 {
-  bool server_op = FALSE, router_op = FALSE;
+  SilcBool server_op = FALSE, router_op = FALSE;
 
   if (mode & SILC_UMODE_SERVER_OPERATOR) {
     /* Cannot set server operator mode (must use OPER command) */
@@ -1455,10 +1363,10 @@ bool silc_server_check_umode_rights(SilcServer server,
    incoming client connection. */
 
 void silc_server_send_connect_notifys(SilcServer server,
-                                     SilcSocketConnection sock,
+                                     SilcPacketStream sock,
                                      SilcClientEntry client)
 {
-  SilcIDListData idata = (SilcIDListData)client;
+  SilcCipher key;
 
   SILC_LOG_DEBUG(("Send welcome notifys"));
 
@@ -1519,11 +1427,12 @@ void silc_server_send_connect_notifys(SilcServer server,
                             server->stat.my_router_ops +
                             server->stat.my_server_ops));
 
+  silc_packet_get_keys(sock, &key, NULL, NULL, NULL);
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your connection is secured with %s cipher, "
                           "key length %d bits",
-                          silc_cipher_get_name(idata->send_key),
-                          silc_cipher_get_key_len(idata->send_key)));
+                          silc_cipher_get_name(key),
+                          silc_cipher_get_key_len(key)));
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your current nickname is %s",
                           client->nickname));
@@ -1559,9 +1468,9 @@ void silc_server_kill_client(SilcServer server,
      to the channel. */
   silc_server_send_notify_on_channels(server, remote_client,
                                      remote_client, SILC_NOTIFY_TYPE_KILLED,
-                                     3, killed->data, killed->len,
+                                     3, killed->data, silc_buffer_len(killed),
                                      comment, comment ? strlen(comment) : 0,
-                                     killer->data, killer->len);
+                                     killer->data, silc_buffer_len(killer));
 
   /* Send KILLED notify to primary route */
   silc_server_send_notify_killed(server, SILC_PRIMARY_ROUTE(server),
@@ -1585,7 +1494,7 @@ void silc_server_kill_client(SilcServer server,
      disconnect the client here */
   if (remote_client->connection) {
     /* Remove locally conneted client */
-    SilcSocketConnection sock = remote_client->connection;
+    SilcPacketStream sock = remote_client->connection;
     silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
     silc_server_close_connection(server, sock);
   } else {
@@ -1632,7 +1541,7 @@ silc_server_check_watcher_list_foreach(void *key, void *context,
 {
   WatcherNotifyContext *notify = user_context;
   SilcClientEntry entry = context;
-  SilcSocketConnection sock;
+  SilcPacketStream sock;
 
   if (!context)
     return;
@@ -1660,7 +1569,7 @@ silc_server_check_watcher_list_foreach(void *key, void *context,
    public key is being watched by someone, and notifies the watcher of the
    notify change of notify type indicated by `notify'. */
 
-bool silc_server_check_watcher_list(SilcServer server,
+SilcBool silc_server_check_watcher_list(SilcServer server,
                                    SilcClientEntry client,
                                    const char *new_nick,
                                    SilcNotifyType notify)
@@ -1711,13 +1620,13 @@ bool silc_server_check_watcher_list(SilcServer server,
 /* Remove the `client' from watcher list. After calling this the `client'
    is not watching any nicknames. */
 
-bool silc_server_del_from_watcher_list(SilcServer server,
+SilcBool silc_server_del_from_watcher_list(SilcServer server,
                                       SilcClientEntry client)
 {
   SilcHashTableList htl;
   void *key;
   SilcClientEntry entry;
-  bool found = FALSE;
+  SilcBool found = FALSE;
 
   silc_hash_table_list(server->watcher_list, &htl);
   while (silc_hash_table_get(&htl, &key, (void *)&entry)) {
@@ -1763,11 +1672,11 @@ bool silc_server_del_from_watcher_list(SilcServer server,
 /* Force the client indicated by `chl' to change the channel user mode
    on channel indicated by `channel' to `forced_mode'. */
 
-bool silc_server_force_cumode_change(SilcServer server,
-                                    SilcSocketConnection sock,
-                                    SilcChannelEntry channel,
-                                    SilcChannelClientEntry chl,
-                                    SilcUInt32 forced_mode)
+SilcBool silc_server_force_cumode_change(SilcServer server,
+                                        SilcPacketStream sock,
+                                        SilcChannelEntry channel,
+                                        SilcChannelClientEntry chl,
+                                        SilcUInt32 forced_mode)
 {
   SilcBuffer idp1, idp2;
   unsigned char cumode[4];
@@ -1784,47 +1693,25 @@ bool silc_server_force_cumode_change(SilcServer server,
   SILC_PUT32_MSB(forced_mode, cumode);
   silc_server_send_notify_to_channel(server, sock, channel, FALSE, TRUE,
                                     SILC_NOTIFY_TYPE_CUMODE_CHANGE,
-                                    3, idp1->data, idp1->len,
+                                    3, idp1->data, silc_buffer_len(idp1),
                                     cumode, sizeof(cumode),
-                                    idp2->data, idp2->len);
+                                    idp2->data, silc_buffer_len(idp2));
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
 
   return TRUE;
 }
 
-/* Find active socket connection by the IP address and port indicated by
-   `ip' and `port', and socket connection type of `type'. */
-
-SilcSocketConnection
-silc_server_find_socket_by_host(SilcServer server,
-                               SilcSocketType type,
-                               const char *ip, SilcUInt16 port)
-{
-  int i;
-
-  for (i = 0; i < server->config->param.connections_max; i++) {
-    if (!server->sockets[i] || SILC_IS_HOST_LOOKUP(server->sockets[i]))
-      continue;
-    if (!strcmp(server->sockets[i]->ip, ip) &&
-       (!port || server->sockets[i]->port == port) &&
-       server->sockets[i]->type == type)
-      return server->sockets[i];
-  }
-
-  return NULL;
-}
-
 /* This function can be used to match the invite and ban lists. */
 
-bool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
-                                SilcUInt8 type, void *check)
+SilcBool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
+                                    SilcUInt8 type, void *check)
 {
   unsigned char *tmp = NULL;
   SilcUInt32 len = 0, t;
   SilcHashTableList htl;
   SilcBuffer entry, idp = NULL, pkp = NULL;
-  bool ret = FALSE;
+  SilcBool ret = FALSE;
 
   SILC_LOG_DEBUG(("Matching invite/ban"));
 
@@ -1837,18 +1724,18 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
       return FALSE;
   }
   if (type == 2) {
-    pkp = silc_pkcs_public_key_payload_encode(check);
+    pkp = silc_public_key_payload_encode(check);
     if (!pkp)
       return FALSE;
     tmp = pkp->data;
-    len = pkp->len;
+    len = silc_buffer_len(pkp);
   }
   if (type == 3) {
     idp = silc_id_payload_encode(check, SILC_ID_CLIENT);
     if (!idp)
       return FALSE;
     tmp = idp->data;
-    len = idp->len;
+    len = silc_buffer_len(idp);
   }
 
   /* Compare the list */
@@ -1877,7 +1764,7 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
 
 /* Process invite or ban information */
 
-bool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
+SilcBool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
                                   SilcUInt8 action, SilcArgumentPayload args)
 {
   unsigned char *tmp;
@@ -1931,7 +1818,7 @@ bool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
        SilcPublicKey pk;
 
        /* Verify validity of the public key */
-       if (!silc_pkcs_public_key_payload_decode(tmp, len, &pk)) {
+       if (!silc_public_key_payload_decode(tmp, len, &pk)) {
          tmp = silc_argument_get_next_arg(args, &type, &len);
          continue;
        }
@@ -2011,7 +1898,7 @@ bool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
        SilcPublicKey pk;
 
        /* Verify validity of the public key */
-       if (!silc_pkcs_public_key_payload_decode(tmp, len, &pk)) {
+       if (!silc_public_key_payload_decode(tmp, len, &pk)) {
          tmp = silc_argument_get_next_arg(args, &type, &len);
          continue;
        }
@@ -2062,9 +1949,8 @@ void silc_server_create_connections(SilcServer server)
 {
   silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_connect_to_router);
-  silc_schedule_task_add(server->schedule, 0,
-                        silc_server_connect_to_router, server, 0, 1,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_connect_to_router, server, 0, 1);
 }
 
 static void
@@ -2092,7 +1978,7 @@ silc_server_process_channel_pk(SilcServer server,
     return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
 
   /* Decode the public key */
-  if (!silc_pkcs_public_key_payload_decode((unsigned char *)pk, pk_len, &chpk))
+  if (!silc_public_key_payload_decode((unsigned char *)pk, pk_len, &chpk))
     return SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY;
 
   /* Create channel public key list (hash table) if needed */
@@ -2109,8 +1995,8 @@ silc_server_process_channel_pk(SilcServer server,
 
   if (type == 0x00) {
     /* Add new public key to channel public key list */
-    SILC_LOG_DEBUG(("Add new channel public key %s to channel %s",
-                   chpk->identifier, channel->channel_name));
+    SILC_LOG_DEBUG(("Add new channel public key to channel %s",
+                   channel->channel_name));
 
     /* Check for resource limit */
     if (silc_hash_table_count(channel->channel_pubkeys) > 64) {
@@ -2141,8 +2027,8 @@ silc_server_process_channel_pk(SilcServer server,
 
 SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
                                           SilcChannelEntry channel,
-                                          bool announce,
-                                          bool delete)
+                                          SilcBool announce,
+                                          SilcBool delete)
 {
   SilcHashTableList htl;
   SilcBuffer list, pkp;
@@ -2163,8 +2049,9 @@ SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
 
   silc_hash_table_list(channel->channel_pubkeys, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&pk)) {
-    pkp = silc_pkcs_public_key_payload_encode(pk);
-    list = silc_argument_payload_encode_one(list, pkp->data, pkp->len,
+    pkp = silc_public_key_payload_encode(pk);
+    list = silc_argument_payload_encode_one(list, pkp->data,
+                                           silc_buffer_len(pkp),
                                            announce ? 0x03 :
                                            delete ? 0x01 : 0x00);
     silc_buffer_free(pkp);
@@ -2177,7 +2064,7 @@ SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
 /* Sets the channel public keys into channel from the list of public keys. */
 
 SilcStatus silc_server_set_channel_pk_list(SilcServer server,
-                                          SilcSocketConnection sender,
+                                          SilcPacketStream sender,
                                           SilcChannelEntry channel,
                                           const unsigned char *pklist,
                                           SilcUInt32 pklist_len)
@@ -2229,7 +2116,7 @@ SilcStatus silc_server_set_channel_pk_list(SilcServer server,
       SILC_PUT32_MSB(channel->user_limit, ulimit);
     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                       SILC_NOTIFY_TYPE_CMODE_CHANGE, 8,
-                                      sidp->data, sidp->len,
+                                      sidp->data, silc_buffer_len(sidp),
                                       mask, 4,
                                       channel->cipher,
                                       channel->cipher ?
@@ -2267,7 +2154,7 @@ SilcStatus silc_server_set_channel_pk_list(SilcServer server,
 /* Verifies the Authentication Payload `auth' with one of the public keys
    on the `channel' public key list. */
 
-bool silc_server_verify_channel_auth(SilcServer server,
+SilcBool silc_server_verify_channel_auth(SilcServer server,
                                     SilcChannelEntry channel,
                                     SilcClientID *client_id,
                                     const unsigned char *auth,
@@ -2277,7 +2164,7 @@ bool silc_server_verify_channel_auth(SilcServer server,
   SilcPublicKey chpk;
   unsigned char *pkhash;
   SilcUInt32 pkhash_len;
-  bool ret = FALSE;
+  SilcBool ret = FALSE;
 
   SILC_LOG_DEBUG(("Verifying channel authentication"));
 
index 1c9c5ee09a5291a1f6e2e8b72115a35bf7e6a294..d468bbdc07e16daa5898c1017efa52cc68d945bb 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
    `router' and are owned by `entry'.  `router' and `entry' can be same
    too.  If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
    distributed to our local clients. */
-bool silc_server_remove_clients_by_server(SilcServer server,
+SilcBool silc_server_remove_clients_by_server(SilcServer server,
                                          SilcServerEntry router,
                                          SilcServerEntry entry,
-                                         bool server_signoff);
+                                         SilcBool server_signoff);
 
 /* Updates the clients that are originated from the `from' to be originated
    from the `to'. If the `resolve_real_server' is TRUE then this will
@@ -39,7 +39,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
 void silc_server_update_clients_by_server(SilcServer server,
                                          SilcServerEntry from,
                                          SilcServerEntry to,
-                                         bool resolve_real_server);
+                                         SilcBool resolve_real_server);
 
 /* Updates servers that are from `from' to be originated from `to'.  This
    will also update the server's connection to `to's connection. */
@@ -51,7 +51,7 @@ void silc_server_update_servers_by_server(SilcServer server,
    can be sent to the servers when `toggle_enabled' is TRUE and will be
    dropped if `toggle_enabled' is FALSE, after this function is called. */
 void silc_server_local_servers_toggle_enabled(SilcServer server,
-                                             bool toggle_enabled);
+                                             SilcBool toggle_enabled);
 
 /* Removes servers that are originated from the `from'.  The server
    entry is deleted in this function.  If `remove_clients' is TRUE then
@@ -60,7 +60,7 @@ void silc_server_local_servers_toggle_enabled(SilcServer server,
    also does not remove locally connected servers. */
 void silc_server_remove_servers_by_server(SilcServer server,
                                          SilcServerEntry from,
-                                         bool remove_clients);
+                                         SilcBool remove_clients);
 
 /* Removes channels that are from `from. */
 void silc_server_remove_channels_by_server(SilcServer server,
@@ -73,31 +73,31 @@ void silc_server_update_channels_by_server(SilcServer server,
 
 /* Checks whether given channel has global users.  If it does this returns
    TRUE and FALSE if there is only locally connected clients on the channel. */
-bool silc_server_channel_has_global(SilcChannelEntry channel);
+SilcBool silc_server_channel_has_global(SilcChannelEntry channel);
 
 /* Checks whether given channel has locally connected users.  If it does this
    returns TRUE and FALSE if there is not one locally connected client. */
-bool silc_server_channel_has_local(SilcChannelEntry channel);
+SilcBool silc_server_channel_has_local(SilcChannelEntry channel);
 
 /* This function removes the channel and all users on the channel, unless
    the channel is permanent.  In this case the channel is disabled but all
    users are removed from the channel.  Returns TRUE if the channel is
    destroyed totally, and FALSE if it is permanent and remains. */
-bool silc_server_channel_delete(SilcServer server,
+SilcBool silc_server_channel_delete(SilcServer server,
                                SilcChannelEntry channel);
 
 /* Returns TRUE if the given client is on the channel.  FALSE if not.
    This works because we assure that the user list on the channel is
    always in up to date thus we can only check the channel list from
    `client' which is faster than checking the user list from `channel'. */
-bool silc_server_client_on_channel(SilcClientEntry client,
+SilcBool silc_server_client_on_channel(SilcClientEntry client,
                                   SilcChannelEntry channel,
                                   SilcChannelClientEntry *chl);
 
 /* Find number of sockets by IP address indicated by `ip'. Returns 0 if
    socket connections with the IP address does not exist. */
 SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
-                                        SilcSocketType type);
+                                        SilcConnectionType type);
 
 /* Find number of sockets by IP address indicated by remote host, indicated
    by `ip' or `hostname', `port', and `type'.  Returns 0 if socket connections
@@ -105,51 +105,40 @@ SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
 SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
                                             const char *ip,
                                             const char *hostname,
-                                            SilcUInt16 port,
-                                            SilcSocketType type);
-
-/* Finds locally cached public key by the public key received in the SKE.
-   If we have it locally cached then we trust it and will use it in the
-   authentication protocol.  Returns the locally cached public key or NULL
-   if we do not find the public key.  */
-SilcPublicKey silc_server_find_public_key(SilcServer server,
-                                         SilcHashTable local_public_keys,
-                                         SilcPublicKey remote_public_key);
-
-/* This returns the first public key from the table of public keys.  This
-   is used only in cases where single public key exists in the table and
-   we want to get a pointer to it.  For public key tables that has multiple
-   keys in it the silc_server_find_public_key must be used. */
+                                            SilcUInt16 port);
+
+/* Get public key by key usage and key context. */
 SilcPublicKey silc_server_get_public_key(SilcServer server,
-                                        SilcHashTable local_public_keys);
+                                        SilcSKRKeyUsage usage,
+                                        void *key_context);
 
 /* Check whether the connection `sock' is allowed to connect to us.  This
    checks for example whether there is too much connections for this host,
    and required version for the host etc. */
-bool silc_server_connection_allowed(SilcServer server,
-                                   SilcSocketConnection sock,
-                                   SilcSocketType type,
-                                   SilcServerConfigConnParams *global,
-                                   SilcServerConfigConnParams *params,
-                                   SilcSKE ske);
+SilcBool silc_server_connection_allowed(SilcServer server,
+                                       SilcPacketStream sock,
+                                       SilcConnectionType type,
+                                       SilcServerConfigConnParams *global,
+                                       SilcServerConfigConnParams *params,
+                                       SilcSKE ske);
 
 /* Checks that client has rights to add or remove channel modes. If any
    of the checks fails FALSE is returned. */
-bool silc_server_check_cmode_rights(SilcServer server,
+SilcBool silc_server_check_cmode_rights(SilcServer server,
                                    SilcChannelEntry channel,
                                    SilcChannelClientEntry client,
                                    SilcUInt32 mode);
 
 /* Check that the client has rights to change its user mode.  Returns
    FALSE if setting some mode is not allowed. */
-bool silc_server_check_umode_rights(SilcServer server,
+SilcBool silc_server_check_umode_rights(SilcServer server,
                                    SilcClientEntry client,
                                    SilcUInt32 mode);
 
 /* This function is used to send the notify packets and motd to the
    incoming client connection. */
 void silc_server_send_connect_notifys(SilcServer server,
-                                     SilcSocketConnection sock,
+                                     SilcPacketStream sock,
                                      SilcClientEntry client);
 
 /* Kill the client indicated by `remote_client' sending KILLED notify
@@ -164,37 +153,37 @@ void silc_server_kill_client(SilcServer server,
 /* This function checks whether the `client' nickname is being watched
    by someone, and notifies the watcher of the notify change of notify
    type indicated by `notify'. */
-bool silc_server_check_watcher_list(SilcServer server,
+SilcBool silc_server_check_watcher_list(SilcServer server,
                                    SilcClientEntry client,
                                    const char *new_nick,
                                    SilcNotifyType notify);
 
 /* Remove the `client' from watcher list. After calling this the `client'
    is not watching any nicknames. */
-bool silc_server_del_from_watcher_list(SilcServer server,
+SilcBool silc_server_del_from_watcher_list(SilcServer server,
                                       SilcClientEntry client);
 
 /* Force the client indicated by `chl' to change the channel user mode
    on channel indicated by `channel' to `forced_mode'. */
-bool silc_server_force_cumode_change(SilcServer server,
-                                    SilcSocketConnection sock,
+SilcBool silc_server_force_cumode_change(SilcServer server,
+                                    SilcPacketStream sock,
                                     SilcChannelEntry channel,
                                     SilcChannelClientEntry chl,
                                     SilcUInt32 forced_mode);
 
 /* Find active socket connection by the IP address and port indicated by
    `ip' and `port', and socket connection type of `type'. */
-SilcSocketConnection
+SilcPacketStream
 silc_server_find_socket_by_host(SilcServer server,
-                               SilcSocketType type,
+                               SilcConnectionType type,
                                const char *ip, SilcUInt16 port);
 
 /* This function can be used to match the invite and ban lists. */
-bool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
+SilcBool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
                                 SilcUInt8 type, void *check);
 
 /* Process invite or ban information */
-bool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
+SilcBool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
                                   SilcUInt8 action, SilcArgumentPayload args);
 
 /* Destructor for invite or ban list entrys */
@@ -215,19 +204,19 @@ silc_server_process_channel_pk(SilcServer server,
 /* Returns the channel public keys as Argument List payload. */
 SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
                                           SilcChannelEntry channel,
-                                          bool announce,
-                                          bool delete);
+                                          SilcBool announce,
+                                          SilcBool delete);
 
 /* Sets the channel public keys into channel from the list of public keys. */
 SilcStatus silc_server_set_channel_pk_list(SilcServer server,
-                                          SilcSocketConnection sender,
+                                          SilcPacketStream sender,
                                           SilcChannelEntry channel,
                                           const unsigned char *pklist,
                                           SilcUInt32 pklist_len);
 
 /* Verifies the Authentication Payload `auth' with one of the public keys
    on the `channel' public key list. */
-bool silc_server_verify_channel_auth(SilcServer server,
+SilcBool silc_server_verify_channel_auth(SilcServer server,
                                     SilcChannelEntry channel,
                                     SilcClientID *client_id,
                                     const unsigned char *auth,
index 2582f6a8d4fdaa56931b10155fb0f87b669549b6..7edfd3a455ef970a3e9605438a6e9eccd769dfdf 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Giovanni Giacobbi <giovanni@giacobbi.net>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 /* Free the authentication fields in the specified struct
  * Expands to two instructions */
 #define CONFIG_FREE_AUTH(__section__)                  \
-  silc_free(__section__->passphrase);                  \
-  if (__section__->publickeys)                         \
-    silc_hash_table_free(__section__->publickeys);
-
-static void my_free_public_key(void *key, void *context, void *user_data)
-{
-  silc_pkcs_public_key_free(context);
-}
+  silc_free(__section__->passphrase);
 
 /* Set default values to those parameters that have not been defined */
 static void
@@ -118,9 +111,25 @@ my_find_param(SilcServerConfig config, const char *name)
   return NULL;
 }
 
+/* SKR find callbcak */
+
+static void my_find_callback(SilcSKR skr, SilcSKRFind find,
+                            SilcSKRStatus status, SilcDList keys,
+                            void *context)
+{
+  SilcSKRStatus *s = context;
+
+  *s = status;
+  if (keys)
+    silc_dlist_uninit(keys);
+
+  silc_skr_find_free(find);
+}
+
 /* parse an authdata according to its auth method */
-static bool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
-                             void **auth_data, SilcUInt32 *auth_data_len)
+static SilcBool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
+                                 void **auth_data, SilcUInt32 *auth_data_len,
+                                 SilcSKRKeyUsage usage, void *key_context)
 {
   if (auth_meth == SILC_AUTH_PASSWORD) {
     /* p is a plain text password */
@@ -139,43 +148,42 @@ static bool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
   } else if (auth_meth == SILC_AUTH_PUBLIC_KEY) {
     /* p is a public key file name */
     SilcPublicKey public_key;
-    SilcPublicKey cached_key;
+    SilcSKR skr = *auth_data;
+    SilcSKRFind find;
+    SilcSKRStatus status;
 
-    if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_PEM))
-      if (!silc_pkcs_load_public_key(p, &public_key, SILC_PKCS_FILE_BIN)) {
-       SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
-                              "Could not load public key file!"));
-       return FALSE;
-      }
+    if (!silc_pkcs_load_public_key(p, &public_key)) {
+      SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                            "Could not load public key file!"));
+      return FALSE;
+    }
 
-    if (*auth_data &&
-       silc_hash_table_find_ext(*auth_data, public_key, (void *)&cached_key,
-                                NULL, silc_hash_public_key, NULL,
-                                silc_hash_public_key_compare, NULL)) {
+    find = silc_skr_find_alloc();
+    silc_skr_find_set_public_key(find, public_key);
+    silc_skr_find_set_usage(find, usage);
+    silc_skr_find_set_context(find, key_context ? key_context : (void *)usage);
+    silc_skr_find(skr, NULL, find, my_find_callback, &status);
+    if (status != SILC_SKR_OK) {
       silc_pkcs_public_key_free(public_key);
       SILC_SERVER_LOG_WARNING(("Warning: public key file \"%s\" already "
                               "configured, ignoring this key", p));
       return TRUE; /* non fatal error */
     }
 
-    /* The auth_data is a pointer to the hash table of public keys. */
-    if (auth_data) {
-      if (*auth_data == NULL)
-       *auth_data = silc_hash_table_alloc(1, silc_hash_public_key, NULL,
-                                          NULL, NULL,
-                                          my_free_public_key, NULL,
-                                          TRUE);
-      SILC_LOG_DEBUG(("Adding public key '%s' to authentication cache",
-                    public_key->identifier));
-      silc_hash_table_add(*auth_data, public_key, public_key);
+    /* Add the public key to repository */
+    if (silc_skr_add_public_key(skr, public_key, usage,
+                               key_context ? key_context : (void *)usage) !=
+       SILC_SKR_OK) {
+      SILC_SERVER_LOG_ERROR(("Error while adding public key \"%s\"", p));
+      return FALSE;
     }
-  } else
-    abort();
+  }
 
   return TRUE;
 }
 
-static bool my_parse_publickeydir(const char *dirname, void **auth_data)
+static SilcBool my_parse_publickeydir(const char *dirname, void **auth_data,
+                                     SilcSKRKeyUsage usage)
 {
   int total = 0;
   struct dirent *get_file;
@@ -207,7 +215,8 @@ static bool my_parse_publickeydir(const char *dirname, void **auth_data)
       SILC_SERVER_LOG_ERROR(("Error stating file %s: %s", buf,
                             strerror(errno)));
     } else if (S_ISREG(check_file.st_mode)) {
-      my_parse_authdata(SILC_AUTH_PUBLIC_KEY, buf, auth_data, NULL);
+      my_parse_authdata(SILC_AUTH_PUBLIC_KEY, buf, auth_data, NULL,
+                       usage, NULL);
       total++;
     }
   }
@@ -228,10 +237,10 @@ SILC_CONFIG_CALLBACK(fetch_generic)
     config->module_path = (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "prefer_passphrase_auth")) {
-    config->prefer_passphrase_auth = *(bool *)val;
+    config->prefer_passphrase_auth = *(SilcBool *)val;
   }
   else if (!strcmp(name, "require_reverse_lookup")) {
-    config->require_reverse_lookup = *(bool *)val;
+    config->require_reverse_lookup = *(SilcBool *)val;
   }
   else if (!strcmp(name, "connections_max")) {
     config->param.connections_max = (SilcUInt32) *(int *)val;
@@ -252,13 +261,13 @@ SILC_CONFIG_CALLBACK(fetch_generic)
     config->param.reconnect_interval_max = (SilcUInt32) *(int *)val;
   }
   else if (!strcmp(name, "reconnect_keep_trying")) {
-    config->param.reconnect_keep_trying = *(bool *)val;
+    config->param.reconnect_keep_trying = *(SilcBool *)val;
   }
   else if (!strcmp(name, "key_exchange_rekey")) {
     config->param.key_exchange_rekey = (SilcUInt32) *(int *)val;
   }
   else if (!strcmp(name, "key_exchange_pfs")) {
-    config->param.key_exchange_pfs = *(bool *)val;
+    config->param.key_exchange_pfs = *(SilcBool *)val;
   }
   else if (!strcmp(name, "channel_rekey_secs")) {
     config->channel_rekey_secs = (SilcUInt32) *(int *)val;
@@ -285,13 +294,13 @@ SILC_CONFIG_CALLBACK(fetch_generic)
       (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "detach_disabled")) {
-    config->detach_disabled = *(bool *)val;
+    config->detach_disabled = *(SilcBool *)val;
   }
   else if (!strcmp(name, "detach_timeout")) {
     config->detach_timeout = (SilcUInt32) *(int *)val;
   }
   else if (!strcmp(name, "qos")) {
-    config->param.qos = *(bool *)val;
+    config->param.qos = *(SilcBool *)val;
   }
   else if (!strcmp(name, "qos_rate_limit")) {
     config->param.qos_rate_limit = *(SilcUInt32 *)val;
@@ -604,13 +613,10 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
     CONFIG_IS_DOUBLE(server_info->public_key);
 
     /* Try to load specified file, if fail stop config parsing */
-    if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
-                                  SILC_PKCS_FILE_PEM))
-      if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
-                                    SILC_PKCS_FILE_BIN)) {
-       SILC_SERVER_LOG_ERROR(("Error: Could not load public key file."));
-       return SILC_CONFIG_EPRINTLINE;
-      }
+    if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key)) {
+      SILC_SERVER_LOG_ERROR(("Error: Could not load public key file."));
+      return SILC_CONFIG_EPRINTLINE;
+    }
   }
   else if (!strcmp(name, "privatekey")) {
     struct stat st;
@@ -628,13 +634,11 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
     }
 
     /* Try to load specified file, if fail stop config parsing */
-    if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
-                                   "", 0, SILC_PKCS_FILE_BIN))
-      if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
-                                     "", 0, SILC_PKCS_FILE_PEM)) {
-       SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
-       return SILC_CONFIG_EPRINTLINE;
-      }
+    if (!silc_pkcs_load_private_key(file_tmp, "", 0,
+                                   &server_info->private_key)) {
+      SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
+      return SILC_CONFIG_EPRINTLINE;
+    }
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -656,10 +660,10 @@ SILC_CONFIG_CALLBACK(fetch_logging)
   SILC_SERVER_CONFIG_SECTION_INIT(SilcServerConfigLogging);
 
   if (!strcmp(name, "timestamp")) {
-    config->logging_timestamp = *(bool *)val;
+    config->logging_timestamp = *(SilcBool *)val;
   }
   else if (!strcmp(name, "quicklogs")) {
-    config->logging_quick = *(bool *)val;
+    config->logging_quick = *(SilcBool *)val;
   }
   else if (!strcmp(name, "flushdelay")) {
     int flushdelay = *(int *)val;
@@ -763,13 +767,13 @@ SILC_CONFIG_CALLBACK(fetch_connparam)
     tmp->reconnect_interval_max = *(SilcUInt32 *)val;
   }
   else if (!strcmp(name, "reconnect_keep_trying")) {
-    tmp->reconnect_keep_trying = *(bool *)val;
+    tmp->reconnect_keep_trying = *(SilcBool *)val;
   }
   else if (!strcmp(name, "key_exchange_rekey")) {
     tmp->key_exchange_rekey = *(SilcUInt32 *)val;
   }
   else if (!strcmp(name, "key_exchange_pfs")) {
-    tmp->key_exchange_pfs = *(bool *)val;
+    tmp->key_exchange_pfs = *(SilcBool *)val;
   }
   else if (!strcmp(name, "version_protocol")) {
     CONFIG_IS_DOUBLE(tmp->version_protocol);
@@ -785,10 +789,10 @@ SILC_CONFIG_CALLBACK(fetch_connparam)
       (*(char *)val ? strdup((char *) val) : NULL);
   }
   else if (!strcmp(name, "anonymous")) {
-    tmp->anonymous = *(bool *)val;
+    tmp->anonymous = *(SilcBool *)val;
   }
   else if (!strcmp(name, "qos")) {
-    tmp->qos = *(bool *)val;
+    tmp->qos = *(SilcBool *)val;
   }
   else if (!strcmp(name, "qos_rate_limit")) {
     tmp->qos_rate_limit = *(SilcUInt32 *)val;
@@ -840,20 +844,23 @@ SILC_CONFIG_CALLBACK(fetch_client)
     CONFIG_IS_DOUBLE(tmp->passphrase);
     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void *)&tmp->passphrase,
-                          &tmp->passphrase_len)) {
+                          &tmp->passphrase_len, 0, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
   else if (!strcmp(name, "publickey")) {
     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
-                          (void *)&tmp->publickeys, NULL)) {
+                          (void *)&config->server->repository, NULL,
+                          SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
   else if (!strcmp(name, "publickeydir")) {
-    if (!my_parse_publickeydir((char *) val, (void *)&tmp->publickeys)) {
+    if (!my_parse_publickeydir((char *) val,
+                              (void *)&config->server->repository,
+                              SILC_SKR_USAGE_KEY_AGREEMENT)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -912,14 +919,15 @@ SILC_CONFIG_CALLBACK(fetch_admin)
     CONFIG_IS_DOUBLE(tmp->passphrase);
     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void *)&tmp->passphrase,
-                          &tmp->passphrase_len)) {
+                          &tmp->passphrase_len, 0, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
   }
   else if (!strcmp(name, "publickey")) {
     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
-                          (void *)&tmp->publickeys, NULL)) {
+                          (void *)&config->server->repository, NULL,
+                          SILC_SKR_USAGE_SERVICE_AUTHORIZATION, tmp)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -1011,7 +1019,7 @@ SILC_CONFIG_CALLBACK(fetch_server)
     CONFIG_IS_DOUBLE(tmp->passphrase);
     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void *)&tmp->passphrase,
-                          &tmp->passphrase_len)) {
+                          &tmp->passphrase_len, 0, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -1019,7 +1027,8 @@ SILC_CONFIG_CALLBACK(fetch_server)
   else if (!strcmp(name, "publickey")) {
     CONFIG_IS_DOUBLE(tmp->publickeys);
     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
-                          (void *)&tmp->publickeys, NULL)) {
+                          (void *)&config->server->repository, NULL,
+                          SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -1033,7 +1042,7 @@ SILC_CONFIG_CALLBACK(fetch_server)
     }
   }
   else if (!strcmp(name, "backup")) {
-    tmp->backup_router = *(bool *)val;
+    tmp->backup_router = *(SilcBool *)val;
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -1087,7 +1096,7 @@ SILC_CONFIG_CALLBACK(fetch_router)
     CONFIG_IS_DOUBLE(tmp->passphrase);
     if (!my_parse_authdata(SILC_AUTH_PASSWORD, (char *) val,
                           (void *)&tmp->passphrase,
-                          &tmp->passphrase_len)) {
+                          &tmp->passphrase_len, 0, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -1095,7 +1104,8 @@ SILC_CONFIG_CALLBACK(fetch_router)
   else if (!strcmp(name, "publickey")) {
     CONFIG_IS_DOUBLE(tmp->publickeys);
     if (!my_parse_authdata(SILC_AUTH_PUBLIC_KEY, (char *) val,
-                          (void *)&tmp->publickeys, NULL)) {
+                          (void *)&config->server->repository, NULL,
+                          SILC_SKR_USAGE_KEY_AGREEMENT, NULL)) {
       got_errno = SILC_CONFIG_EPRINTLINE;
       goto got_err;
     }
@@ -1109,7 +1119,7 @@ SILC_CONFIG_CALLBACK(fetch_router)
     }
   }
   else if (!strcmp(name, "initiator")) {
-    tmp->initiator = *(bool *)val;
+    tmp->initiator = *(SilcBool *)val;
   }
   else if (!strcmp(name, "backuphost")) {
     CONFIG_IS_DOUBLE(tmp->backup_replace_ip);
@@ -1128,7 +1138,7 @@ SILC_CONFIG_CALLBACK(fetch_router)
     tmp->backup_replace_port = (SilcUInt16) port;
   }
   else if (!strcmp(name, "backuplocal")) {
-    tmp->backup_local = *(bool *)val;
+    tmp->backup_local = *(SilcBool *)val;
   }
   else
     return SILC_CONFIG_EINTERNAL;
@@ -1353,12 +1363,12 @@ static void silc_server_config_set_defaults(SilcServerConfig config)
 
 /* Check for correctness of the configuration */
 
-static bool silc_server_config_check(SilcServerConfig config)
+static SilcBool silc_server_config_check(SilcServerConfig config)
 {
-  bool ret = TRUE;
+  SilcBool ret = TRUE;
   SilcServerConfigServer *s;
   SilcServerConfigRouter *r;
-  bool b = FALSE;
+  SilcBool b = FALSE;
 
   /* ServerConfig is mandatory */
   if (!config->server_info) {
@@ -1440,7 +1450,8 @@ static bool silc_server_config_check(SilcServerConfig config)
    configuration object. The SilcServerConfig must be freed by calling
    the silc_server_config_destroy function. */
 
-SilcServerConfig silc_server_config_alloc(const char *filename)
+SilcServerConfig silc_server_config_alloc(const char *filename,
+                                         SilcServer server)
 {
   SilcServerConfig config_new;
   SilcConfigEntity ent;
@@ -1457,6 +1468,7 @@ SilcServerConfig silc_server_config_alloc(const char *filename)
   config_new->refcount = 1;
   config_new->logging_timestamp = TRUE;
   config_new->param.reconnect_keep_trying = TRUE;
+  config_new->server = server;
 
   /* obtain a config file object */
   file = silc_config_open(filename);
@@ -1666,7 +1678,7 @@ void silc_server_config_destroy(SilcServerConfig config)
 /* Registers configured ciphers. These can then be allocated by the
    server when needed. */
 
-bool silc_server_config_register_ciphers(SilcServer server)
+SilcBool silc_server_config_register_ciphers(SilcServer server)
 {
   SilcServerConfig config = server->config;
   SilcServerConfigCipher *cipher = config->cipher;
@@ -1692,70 +1704,6 @@ bool silc_server_config_register_ciphers(SilcServer server)
        silc_server_stop(server);
        exit(1);
       }
-    } else {
-#ifdef SILC_SIM
-      /* Load (try at least) the crypto SIM module */
-      char buf[1023], *alg_name;
-      SilcCipherObject cipher_obj;
-      SilcSim sim;
-
-      memset(&cipher_obj, 0, sizeof(cipher_obj));
-      cipher_obj.name = cipher->name;
-      cipher_obj.block_len = cipher->block_length;
-      cipher_obj.key_len = cipher->key_length * 8;
-
-      /* build the libname */
-      snprintf(buf, sizeof(buf), "%s/%s", config->module_path,
-               cipher->module);
-      sim = silc_sim_alloc(SILC_SIM_CIPHER, buf, 0);
-
-      alg_name = strdup(cipher->name);
-      if (strchr(alg_name, '-'))
-       *strchr(alg_name, '-') = '\0';
-
-      if (silc_sim_load(sim)) {
-       cipher_obj.set_key =
-         silc_sim_getsym(sim, silc_sim_symname(alg_name,
-                                               SILC_CIPHER_SIM_SET_KEY));
-       SILC_LOG_DEBUG(("set_key=%p", cipher_obj.set_key));
-       cipher_obj.set_key_with_string =
-         silc_sim_getsym(sim,
-           silc_sim_symname(alg_name,
-             SILC_CIPHER_SIM_SET_KEY_WITH_STRING));
-       SILC_LOG_DEBUG(("set_key_with_string=%p",
-         cipher_obj.set_key_with_string));
-       cipher_obj.encrypt =
-         silc_sim_getsym(sim, silc_sim_symname(alg_name,
-                                               SILC_CIPHER_SIM_ENCRYPT_CBC));
-       SILC_LOG_DEBUG(("encrypt_cbc=%p", cipher_obj.encrypt));
-        cipher_obj.decrypt =
-         silc_sim_getsym(sim, silc_sim_symname(alg_name,
-                                               SILC_CIPHER_SIM_DECRYPT_CBC));
-       SILC_LOG_DEBUG(("decrypt_cbc=%p", cipher_obj.decrypt));
-        cipher_obj.context_len =
-         silc_sim_getsym(sim, silc_sim_symname(alg_name,
-                                               SILC_CIPHER_SIM_CONTEXT_LEN));
-       SILC_LOG_DEBUG(("context_len=%p", cipher_obj.context_len));
-
-       /* Put the SIM to the list of all SIM's in server */
-       silc_dlist_add(server->sim, sim);
-
-       silc_free(alg_name);
-      } else {
-       SILC_LOG_ERROR(("Error configuring ciphers"));
-        silc_sim_free(sim);
-       silc_server_stop(server);
-       exit(1);
-      }
-
-      /* Register the cipher */
-      silc_cipher_register(&cipher_obj);
-#else
-      SILC_LOG_ERROR(("Dynamic module support not compiled, "
-                       "can't load modules!"));
-      silc_server_stop(server);
-      exit(1);
-#endif
     }
     cipher = cipher->next;
   } /* while */
@@ -1766,7 +1714,7 @@ bool silc_server_config_register_ciphers(SilcServer server)
 /* Registers configured hash functions. These can then be allocated by the
    server when needed. */
 
-bool silc_server_config_register_hashfuncs(SilcServer server)
+SilcBool silc_server_config_register_hashfuncs(SilcServer server)
 {
   SilcServerConfig config = server->config;
   SilcServerConfigHash *hash = config->hash;
@@ -1792,54 +1740,6 @@ bool silc_server_config_register_hashfuncs(SilcServer server)
        silc_server_stop(server);
        exit(1);
       }
-    } else {
-#ifdef SILC_SIM
-      /* Load (try at least) the hash SIM module */
-      SilcHashObject hash_obj;
-      SilcSim sim;
-
-      memset(&hash_obj, 0, sizeof(hash_obj));
-      hash_obj.name = hash->name;
-      hash_obj.block_len = hash->block_length;
-      hash_obj.hash_len = hash->digest_length;
-
-      sim = silc_sim_alloc(SILC_SIM_HASH, hash->module, 0);
-
-      if ((silc_sim_load(sim))) {
-       hash_obj.init =
-         silc_sim_getsym(sim, silc_sim_symname(hash->name,
-                                               SILC_HASH_SIM_INIT));
-       SILC_LOG_DEBUG(("init=%p", hash_obj.init));
-       hash_obj.update =
-         silc_sim_getsym(sim, silc_sim_symname(hash->name,
-                                               SILC_HASH_SIM_UPDATE));
-       SILC_LOG_DEBUG(("update=%p", hash_obj.update));
-        hash_obj.final =
-         silc_sim_getsym(sim, silc_sim_symname(hash->name,
-                                               SILC_HASH_SIM_FINAL));
-       SILC_LOG_DEBUG(("final=%p", hash_obj.final));
-        hash_obj.context_len =
-         silc_sim_getsym(sim, silc_sim_symname(hash->name,
-                                               SILC_HASH_SIM_CONTEXT_LEN));
-       SILC_LOG_DEBUG(("context_len=%p", hash_obj.context_len));
-
-       /* Put the SIM to the table of all SIM's in server */
-       silc_dlist_add(server->sim, sim);
-      } else {
-       SILC_LOG_ERROR(("Error configuring hash functions"));
-        silc_sim_free(sim);
-       silc_server_stop(server);
-       exit(1);
-      }
-
-      /* Register the hash function */
-      silc_hash_register(&hash_obj);
-#else
-      SILC_LOG_ERROR(("Dynamic module support not compiled, "
-                       "can't load modules!"));
-      silc_server_stop(server);
-      exit(1);
-#endif
     }
     hash = hash->next;
   } /* while */
@@ -1850,7 +1750,7 @@ bool silc_server_config_register_hashfuncs(SilcServer server)
 /* Registers configure HMACs. These can then be allocated by the server
    when needed. */
 
-bool silc_server_config_register_hmacs(SilcServer server)
+SilcBool silc_server_config_register_hmacs(SilcServer server)
 {
   SilcServerConfig config = server->config;
   SilcServerConfigHmac *hmac = config->hmac;
@@ -1882,31 +1782,8 @@ bool silc_server_config_register_hmacs(SilcServer server)
 
 /* Registers configured PKCS's. */
 
-bool silc_server_config_register_pkcs(SilcServer server)
+SilcBool silc_server_config_register_pkcs(SilcServer server)
 {
-  SilcServerConfig config = server->config;
-  SilcServerConfigPkcs *pkcs = config->pkcs;
-
-  SILC_LOG_DEBUG(("Registering configured PKCS"));
-
-  if (!pkcs)
-    return FALSE;
-
-  while (pkcs) {
-    int i;
-    for (i = 0; silc_default_pkcs[i].name; i++)
-      if (!strcmp(silc_default_pkcs[i].name, pkcs->name)) {
-       silc_pkcs_register((SilcPKCSObject *)&silc_default_pkcs[i]);
-       break;
-      }
-    if (!silc_pkcs_is_supported(pkcs->name)) {
-      SILC_LOG_ERROR(("Unknown PKCS `%s'", pkcs->name));
-      silc_server_stop(server);
-      exit(1);
-    }
-    pkcs = pkcs->next;
-  } /* while */
-
   return TRUE;
 }
 
@@ -2094,12 +1971,12 @@ silc_server_config_find_backup_conn(SilcServer server, char *host)
 /* Returns TRUE if configuration for a router connection that we are
    initiating exists. */
 
-bool silc_server_config_is_primary_route(SilcServer server)
+SilcBool silc_server_config_is_primary_route(SilcServer server)
 {
   SilcServerConfig config = server->config;
   SilcServerConfigRouter *serv = NULL;
   int i;
-  bool found = FALSE;
+  SilcBool found = FALSE;
 
   serv = config->routers;
   for (i = 0; serv; i++) {
index cc1ecb21bcd8268309cf3d7c4627bb4736348140..aa7956cbd273cf1ec1b797cab7df69694fe1e79b 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Giovanni Giacobbi <giovanni@giacobbi.net>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -105,7 +105,7 @@ typedef struct SilcServerConfigClientStruct {
   char *host;
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
-  SilcHashTable publickeys;
+  SilcBool publickeys;
   SilcServerConfigConnParams *param;
   struct SilcServerConfigClientStruct *next;
 } SilcServerConfigClient;
@@ -117,7 +117,7 @@ typedef struct SilcServerConfigAdminStruct {
   char *nick;
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
-  SilcHashTable publickeys;
+  SilcBool publickeys;
   struct SilcServerConfigAdminStruct *next;
 } SilcServerConfigAdmin;
 
@@ -133,9 +133,9 @@ typedef struct SilcServerConfigServerStruct {
   char *host;
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
-  SilcHashTable publickeys;
+  SilcBool publickeys;
   SilcServerConfigConnParams *param;
-  bool backup_router;
+  SilcBool backup_router;
   struct SilcServerConfigServerStruct *next;
 } SilcServerConfigServer;
 
@@ -144,19 +144,20 @@ typedef struct SilcServerConfigRouterStruct {
   char *host;
   unsigned char *passphrase;
   SilcUInt32 passphrase_len;
-  SilcHashTable publickeys;
+  SilcBool publickeys;
   SilcUInt16 port;
   SilcServerConfigConnParams *param;
-  bool initiator;
-  bool backup_router;
+  SilcBool initiator;
+  SilcBool backup_router;
   char *backup_replace_ip;
   SilcUInt16 backup_replace_port;
-  bool backup_local;
+  SilcBool backup_local;
   struct SilcServerConfigRouterStruct *next;
 } SilcServerConfigRouter;
 
 /* define the SilcServerConfig object */
 typedef struct {
+  SilcServer server;
   void *tmp;
 
   /* Reference count (when this reaches zero, config object is destroyed) */
@@ -164,16 +165,16 @@ typedef struct {
 
   /* The General section */
   char *module_path;
-  bool prefer_passphrase_auth;
-  bool require_reverse_lookup;
+  SilcBool prefer_passphrase_auth;
+  SilcBool require_reverse_lookup;
   SilcUInt32 channel_rekey_secs;
   SilcUInt32 key_exchange_timeout;
   SilcUInt32 conn_auth_timeout;
   SilcServerConfigConnParams param;
-  bool detach_disabled;
+  SilcBool detach_disabled;
   SilcUInt32 detach_timeout;
-  bool logging_timestamp;
-  bool logging_quick;
+  SilcBool logging_timestamp;
+  SilcBool logging_quick;
   long logging_flushdelay;
   char *debug_string;
 
@@ -203,17 +204,18 @@ typedef struct {
 /* Prototypes */
 
 /* Basic config operations */
-SilcServerConfig silc_server_config_alloc(const char *filename);
+SilcServerConfig silc_server_config_alloc(const char *filename,
+                                         SilcServer server);
 void silc_server_config_destroy(SilcServerConfig config);
 void silc_server_config_ref(SilcServerConfigRef *ref, SilcServerConfig config,
                            void *ref_ptr);
 void silc_server_config_unref(SilcServerConfigRef *ref);
 
 /* Algorithm registering and reset functions */
-bool silc_server_config_register_ciphers(SilcServer server);
-bool silc_server_config_register_hashfuncs(SilcServer server);
-bool silc_server_config_register_hmacs(SilcServer server);
-bool silc_server_config_register_pkcs(SilcServer server);
+SilcBool silc_server_config_register_ciphers(SilcServer server);
+SilcBool silc_server_config_register_hashfuncs(SilcServer server);
+SilcBool silc_server_config_register_hmacs(SilcServer server);
+SilcBool silc_server_config_register_pkcs(SilcServer server);
 void silc_server_config_setlogfiles(SilcServer server);
 
 /* Run-time config access functions */
@@ -230,7 +232,7 @@ SilcServerConfigRouter *
 silc_server_config_find_router_conn(SilcServer server, char *host, int port);
 SilcServerConfigRouter *
 silc_server_config_find_backup_conn(SilcServer server, char *host);
-bool silc_server_config_is_primary_route(SilcServer server);
+SilcBool silc_server_config_is_primary_route(SilcServer server);
 SilcServerConfigRouter *
 silc_server_config_get_primary_router(SilcServer server);
 SilcServerConfigRouter *
index 3d4ea8e0970aedbde57203aa4ef8ab332ea2e64c..f840cab92e508a2b5ced3084607fd2e1ac48c4b6 100644 (file)
@@ -54,14 +54,14 @@ void silc_id_create_server_id(const char *ip, SilcUInt16 port, SilcRng rng,
    caller must recall the function with different nickname. If this returns
    TRUE the new ID was created successfully. */
 
-bool silc_id_create_client_id(SilcServer server,
-                             SilcServerID *server_id, SilcRng rng,
-                             SilcHash md5hash,
-                             unsigned char *nickname, SilcUInt32 nick_len,
-                             SilcClientID **new_id)
+SilcBool silc_id_create_client_id(SilcServer server,
+                                 SilcServerID *server_id, SilcRng rng,
+                                 SilcHash md5hash,
+                                 unsigned char *nickname, SilcUInt32 nick_len,
+                                 SilcClientID **new_id)
 {
   unsigned char hash[16];
-  bool finding = FALSE;
+  SilcBool finding = FALSE;
 
   SILC_LOG_DEBUG(("Creating new Client ID"));
 
@@ -107,11 +107,11 @@ bool silc_id_create_client_id(SilcServer server,
 
 /* Creates Channel ID */
 
-bool silc_id_create_channel_id(SilcServer server,
-                              SilcServerID *router_id, SilcRng rng,
-                              SilcChannelID **new_id)
+SilcBool silc_id_create_channel_id(SilcServer server,
+                                  SilcServerID *router_id, SilcRng rng,
+                                  SilcChannelID **new_id)
 {
-  bool finding = TRUE;
+  SilcBool finding = TRUE;
 
   SILC_LOG_DEBUG(("Creating new Channel ID"));
 
@@ -148,16 +148,19 @@ bool silc_id_create_channel_id(SilcServer server,
 /* Checks whether the `server_id' is valid.  It must be based to the
    IP address provided in the `remote' socket connection. */
 
-bool silc_id_is_valid_server_id(SilcServer server,
-                               SilcServerID *server_id,
-                               SilcSocketConnection remote)
+SilcBool silc_id_is_valid_server_id(SilcServer server,
+                                   SilcServerID *server_id,
+                                   SilcPacketStream remote)
 {
   unsigned char ip[16];
+  const char *remote_ip;
+  SilcStream stream = silc_packet_stream_get_stream(remote);
 
-  if (!silc_net_addr2bin(remote->ip, ip, sizeof(ip)))
+  silc_socket_stream_get_info(stream, NULL, NULL, &remote_ip, NULL);
+  if (!silc_net_addr2bin(remote_ip, ip, sizeof(ip)))
     return FALSE;
 
-  if (silc_net_is_ip4(remote->ip)) {
+  if (silc_net_is_ip4(remote_ip)) {
     if (!memcmp(server_id->ip.data, ip, 4))
       return TRUE;
   } else {
index 4f81aa17ad0421658036e59e0b044abccdbe2983..c4e1762f6bf97bed18f293493ed9caaf2e8f1003 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 /* Prototypes */
 void silc_id_create_server_id(const char *ip, SilcUInt16 port, SilcRng rng,
                              SilcServerID **new_id);
-bool silc_id_create_client_id(SilcServer server,
-                             SilcServerID *server_id, SilcRng rng,
-                             SilcHash md5hash, unsigned char *nickname,
-                             SilcUInt32 nick_len,
-                             SilcClientID **new_id);
-bool silc_id_create_channel_id(SilcServer server,
-                              SilcServerID *router_id, SilcRng rng,
-                              SilcChannelID **new_id);
-bool silc_id_is_valid_server_id(SilcServer server,
-                               SilcServerID *server_id,
-                               SilcSocketConnection remote);
+SilcBool silc_id_create_client_id(SilcServer server,
+                                 SilcServerID *server_id, SilcRng rng,
+                                 SilcHash md5hash, unsigned char *nickname,
+                                 SilcUInt32 nick_len,
+                                 SilcClientID **new_id);
+SilcBool silc_id_create_channel_id(SilcServer server,
+                                  SilcServerID *router_id, SilcRng rng,
+                                  SilcChannelID **new_id);
+SilcBool silc_id_is_valid_server_id(SilcServer server,
+                                   SilcServerID *server_id,
+                                   SilcPacketStream remote);
 
 #endif
index fede33164e63d5a84f82b158b3c85f90858e5960..b3fc3fd232b4223a3df6b4752e9f5a6e24f8f123 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
-  
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -22,7 +22,7 @@
 #define SERVERINCLUDES_H
 
 /* Generic includes */
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Forward declaration for SILC Server object. The actual object is
    defined in internal header file for server routines. I want to keep
 typedef struct SilcServerStruct *SilcServer;
 
 /* SILC Server includes */
-#include "idlist.h"
 #include "serverconfig.h"
 #include "server.h"
+#include "idlist.h"
 #include "serverid.h"
 #include "server_util.h"
 #include "packet_send.h"
 #include "packet_receive.h"
 #include "route.h"
-#include "protocol.h"
 #include "command.h"
 #include "command_reply.h"
 #include "server_query.h"
index 2ab5106562a6a6d202937d438349cf2297183f8c..0c95b743bd977b82151f7b3c88036193b466f5be 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -234,12 +234,6 @@ static void silc_server_daemonise(SilcServer server)
      to stderr are changed to SILC_SERVER_LOG_ERROR() */
 }
 
-static void signal_handler(int sig)
-{
-  /* Mark the signal to be caller after this signal is over. */
-  silc_schedule_signal_call(silcd->schedule, sig);
-}
-
 SILC_TASK_CALLBACK(got_hup)
 {
   /* First, reset all log files (they might have been deleted) */
@@ -333,10 +327,11 @@ SILC_TASK_CALLBACK(dump_stats)
     fprintf(fdd, "  primary router         : %s\n",
       silcd->router->server_name ? silcd->router->server_name : "");
 
+#if 0
   /* Dump socket connections */
   {
     int i;
-    SilcSocketConnection s;
+    SilcPacketStream s;
 
     fprintf(fdd, "\nDumping socket connections\n");
     for (i = 0; i < silcd->config->param.connections_max; i++) {
@@ -349,10 +344,11 @@ SILC_TASK_CALLBACK(dump_stats)
              (unsigned int)s->flags);
     }
   }
+#endif
 
   /* Dump lists */
   {
-    SilcIDCacheList list = NULL;
+    SilcList list;
     SilcIDCacheEntry id_cache = NULL;
     SilcServerEntry server_entry;
     SilcClientEntry client_entry;
@@ -362,46 +358,35 @@ SILC_TASK_CALLBACK(dump_stats)
     fprintf(fdd, "\nDumping databases\n");
 
     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
-      if (silc_idcache_list_first(list, &id_cache)) {
-       fprintf(fdd, "\nServers in local-list:\n");
-       c = 1;
-       while (id_cache) {
+      c = 1;
+      fprintf(fdd, "\nServers in local-list:\n");
+      while ((id_cache = silc_list_get(list))) {
          server_entry = (SilcServerEntry)id_cache->context;
          fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
                  server_entry->server_name ? server_entry->server_name :
                  "N/A", server_entry->id ?
                  silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
                  server_entry->data.status);
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
          c++;
-       }
       }
-      silc_idcache_list_free(list);
     }
     if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
-      if (silc_idcache_list_first(list, &id_cache)) {
        fprintf(fdd, "\nServers in global-list:\n");
        c = 1;
-       while (id_cache) {
+        while ((id_cache = silc_list_get(list))) {
          server_entry = (SilcServerEntry)id_cache->context;
          fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
                  server_entry->server_name ? server_entry->server_name :
                  "N/A", server_entry->id ?
                  silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
                  server_entry->data.status);
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
          c++;
-       }
-      }
-      silc_idcache_list_free(list);
+        }
     }
     if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
-      if (silc_idcache_list_first(list, &id_cache)) {
        fprintf(fdd, "\nClients in local-list:\n");
        c = 1;
-       while (id_cache) {
+        while ((id_cache = silc_list_get(list))) {
          client_entry = (SilcClientEntry)id_cache->context;
          server_entry = client_entry->router;
          fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
@@ -411,18 +396,13 @@ SILC_TASK_CALLBACK(dump_stats)
                  client_entry->data.status, server_entry ?
                  server_entry->server_name ? server_entry->server_name :
                  "N/A" : "local");
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
          c++;
        }
-      }
-      silc_idcache_list_free(list);
     }
     if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
-      if (silc_idcache_list_first(list, &id_cache)) {
        fprintf(fdd, "\nClients in global-list:\n");
        c = 1;
-       while (id_cache) {
+        while ((id_cache = silc_list_get(list))) {
          client_entry = (SilcClientEntry)id_cache->context;
          server_entry = client_entry->router;
          fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
@@ -432,46 +412,32 @@ SILC_TASK_CALLBACK(dump_stats)
                  client_entry->data.status, server_entry ?
                  server_entry->server_name ? server_entry->server_name :
                  "N/A" : "local");
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
          c++;
        }
-      }
-      silc_idcache_list_free(list);
     }
     if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
-      if (silc_idcache_list_first(list, &id_cache)) {
        fprintf(fdd, "\nChannels in local-list:\n");
        c = 1;
-       while (id_cache) {
+        while ((id_cache = silc_list_get(list))) {
          channel_entry = (SilcChannelEntry)id_cache->context;
          fprintf(fdd, "  %d: name %s id %s\n", c,
                  channel_entry->channel_name ? channel_entry->channel_name :
                  "N/A", channel_entry->id ?
                  silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
          c++;
        }
-      }
-      silc_idcache_list_free(list);
     }
     if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
-      if (silc_idcache_list_first(list, &id_cache)) {
        fprintf(fdd, "\nChannels in global-list:\n");
        c = 1;
-       while (id_cache) {
+        while ((id_cache = silc_list_get(list))) {
          channel_entry = (SilcChannelEntry)id_cache->context;
          fprintf(fdd, "  %d: name %s id %s\n", c,
                  channel_entry->channel_name ? channel_entry->channel_name :
                  "N/A", channel_entry->id ?
                  silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
-         if (!silc_idcache_list_next(list, &id_cache))
-           break;
          c++;
        }
-      }
-      silc_idcache_list_free(list);
     }
   }
 #endif
@@ -593,8 +559,8 @@ void silc_server_stderr(SilcLogType type, char *message)
 int main(int argc, char **argv)
 {
   int ret, opt, option_index;
-  bool foreground = FALSE;
-  bool opt_create_keypair = FALSE;
+  SilcBool foreground = FALSE;
+  SilcBool opt_create_keypair = FALSE;
   char *silcd_config_file = NULL;
   struct sigaction sa;
 
@@ -614,7 +580,7 @@ int main(int argc, char **argv)
          printf("SILCd Secure Internet Live Conferencing daemon, "
                 "version %s (base: SILC Toolkit %s)\n",
                 silc_dist_version, silc_version);
-         printf("(c) 1997 - 2005 Pekka Riikonen "
+         printf("(c) 1997 - 2007 Pekka Riikonen "
                 "<priikone@silcnet.org>\n");
          exit(0);
          break;
@@ -705,7 +671,7 @@ int main(int argc, char **argv)
     silc_hash_register_default();
     silc_hmac_register_default();
     silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
-                        opt_identifier, "", NULL, NULL, NULL, FALSE);
+                        opt_identifier, "", NULL, NULL, FALSE);
     exit(0);
   }
 
@@ -726,7 +692,7 @@ int main(int argc, char **argv)
   silc_hmac_register_default();
 
   /* Read configuration files */
-  silcd->config = silc_server_config_alloc(silcd_config_file);
+  silcd->config = silc_server_config_alloc(silcd_config_file, silcd);
   if (silcd->config == NULL)
     goto fail;
   silcd->config_file = silcd_config_file;
@@ -759,15 +725,10 @@ int main(int argc, char **argv)
 #endif /* SIGXCPU */
 
   /* Handle specificly some other signals. */
-  sa.sa_handler = signal_handler;
-  sigaction(SIGHUP, &sa, NULL);
-  sigaction(SIGTERM, &sa, NULL);
-  sigaction(SIGINT, &sa, NULL);
-  sigaction(SIGUSR1, &sa, NULL);
-  silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
-  silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
-  silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
-  silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
+  silc_schedule_task_add_signal(silcd->schedule, SIGHUP, got_hup, NULL);
+  silc_schedule_task_add_signal(silcd->schedule, SIGTERM, stop_server, NULL);
+  silc_schedule_task_add_signal(silcd->schedule, SIGINT, stop_server, NULL);
+  silc_schedule_task_add_signal(silcd->schedule, SIGUSR1, dump_stats, NULL);
 
   if (!foreground) {
     /* Before running the server, fork to background. */
index 72ddc7d11e9f05d81ba3395a5b969fe48b0e6784..64b1326ee64e8c0dcebc27cd58942690beacc390 100644 (file)
@@ -10,7 +10,7 @@
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
-  
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -31,6 +31,4 @@
 #define SILC_SERVER_PUBLIC_KEY_NAME "/silcd.pub"
 #define SILC_SERVER_PRIVATE_KEY_NAME "/silcd.prv"
 
-#define SERVER_KEY_EXPIRATION_DAYS 180
-
 #endif