More SILC Server 1.1 porting. Added HTTP statistics access.
[silc.git] / apps / silcd / server.c
index 5c9078a28af5e94d7427b641b1ded83987077876..16d2298881a375e8e088cd4ed047529175e3df1e 100644 (file)
 #include "serverincludes.h"
 #include "server_internal.h"
 
-/************************* Types and definitions ***************************/
+/************************* Types and definitions ****************************/
 
 SILC_TASK_CALLBACK(silc_server_get_stats);
 SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_do_rekey);
+SILC_TASK_CALLBACK(silc_server_purge_expired_clients);
 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);
+static void silc_server_rekey(SilcServer server, SilcPacketStream sock,
+                             SilcPacket packet);
 
 
 /************************ Static utility functions **************************/
@@ -96,6 +99,7 @@ static SilcBool silc_server_packet_receive(SilcPacketEngine engine,
        !(idata->status & SILC_IDLIST_STATUS_REGISTERED)) &&
       packet->type != SILC_PACKET_NEW_CLIENT &&
       packet->type != SILC_PACKET_NEW_SERVER &&
+      packet->type != SILC_PACKET_CONNECTION_AUTH_REQUEST &&
       packet->type != SILC_PACKET_DISCONNECT)
     return FALSE;
 
@@ -106,6 +110,68 @@ static SilcBool silc_server_packet_receive(SilcPacketEngine engine,
       (idata->status & SILC_IDLIST_STATUS_REGISTERED))
     return FALSE;
 
+  /* Ignore packets from disabled connection */
+  if (idata->status & SILC_IDLIST_STATUS_DISABLED &&
+      packet->type != SILC_PACKET_HEARTBEAT &&
+      packet->type != SILC_PACKET_RESUME_ROUTER &&
+      packet->type != SILC_PACKET_REKEY)
+    return FALSE;
+
+  /* Check that the the current client ID is same as in the client's packet. */
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    SilcClientEntry client = (SilcClientEntry)silc_packet_get_context(stream);
+    SilcClientID client_id;
+
+    if (client->id && packet->src_id &&
+       silc_id_str2id(packet->src_id, packet->src_id_len,
+                      packet->src_id_type, &client_id, sizeof(client_id))) {
+      if (!SILC_ID_CLIENT_COMPARE(client->id, &client_id)) {
+       SILC_LOG_DEBUG(("Packet source is not same as sender"));
+       return FALSE;
+      }
+    }
+  }
+
+  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 &&
+       idata->conn_type != SILC_CONN_CLIENT &&
+       memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
+      SilcPacketStream conn;
+      SilcServerID server_id;
+
+      silc_id_str2id(packet->dst_id, packet->dst_id_len, packet->dst_id_type,
+                    &server_id, sizeof(server_id));
+
+      conn = silc_server_route_get(server, &server_id, SILC_ID_SERVER);
+      if (!conn) {
+       SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
+                         silc_id_render(&server_id, SILC_ID_SERVER)));
+       return FALSE;
+      }
+
+      silc_server_packet_route(server, conn, packet);
+      silc_packet_free(packet);
+      return TRUE;
+    }
+  }
+
+  /* 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 &&
+      idata->conn_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, stream, packet);
+  }
+
   /* Process packet */
   silc_server_packet_parse_type(server, stream, packet);
 
@@ -119,7 +185,30 @@ static void silc_server_packet_eos(SilcPacketEngine engine,
                                   void *callback_context,
                                   void *stream_context)
 {
+  SilcServer server = callback_context;
+  SilcIDListData idata = silc_packet_get_context(stream);
+
   SILC_LOG_DEBUG(("End of stream received"));
+
+  if (!idata)
+    return;
+
+  if (server->router_conn && server->router_conn->sock == stream &&
+      !server->router && server->standalone) {
+    silc_server_create_connections(server);
+  } else {
+    /* If backup disconnected then mark that resuming will not be allowed */
+     if (server->server_type == SILC_ROUTER && !server->backup_router &&
+         idata->conn_type == SILC_CONN_SERVER) {
+      SilcServerEntry server_entry = (SilcServerEntry)idata;
+      if (server_entry->server_type == SILC_BACKUP_ROUTER)
+        server->backup_closed = TRUE;
+    }
+
+    silc_server_free_sock_user_data(server, stream, NULL);
+  }
+
+  silc_server_close_connection(server, stream);
 }
 
 /* Packet engine callback to indicate error */
@@ -130,7 +219,20 @@ static void silc_server_packet_error(SilcPacketEngine engine,
                                     void *callback_context,
                                     void *stream_context)
 {
+  SilcIDListData idata = silc_packet_get_context(stream);
+  SilcStream sock = silc_packet_stream_get_stream(stream);
+  const char *ip;
+  SilcUInt16 port;
+
+  if (!idata || !sock)
+    return;
 
+  if (!silc_socket_stream_get_info(sock, NULL, NULL, &ip, &port))
+    return;
+
+  SILC_LOG_ERROR(("Connection %s:%d [%s]: %s",
+                 SILC_CONNTYPE_STRING(idata->conn_type), ip, port,
+                 silc_packet_error_string(error)));
 }
 
 /* Packet stream callbacks */
@@ -226,6 +328,7 @@ static void silc_server_packet_parse_type(SilcServer server,
     {
       SilcStatus status;
       char *message = NULL;
+      const char *hostname, *ip;
 
       if (packet->flags & SILC_PACKET_FLAG_LIST)
        break;
@@ -238,12 +341,13 @@ static void silc_server_packet_parse_type(SilcServer server,
        message = silc_memdup(packet->buffer.data + 1,
                              silc_buffer_len(&packet->buffer) - 1);
 
-#if 0
-      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
-                    sock->ip, sock->hostname,
+      if (!silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL))
+       break;
+
+      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s", ip, hostname,
                     silc_get_status_message(status), status,
                     message ? message : ""));
-#endif
+
       silc_free(message);
 
       /* Do not switch to backup in case of error */
@@ -371,7 +475,7 @@ static void silc_server_packet_parse_type(SilcServer server,
      */
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
-    /* XXX handle rekey */
+    silc_server_rekey(server, sock, packet);
     break;
 
   case SILC_PACKET_FTP:
@@ -437,6 +541,12 @@ SilcBool silc_server_alloc(SilcServer *new_server)
   server->repository = silc_skr_alloc();
   if (!server->repository)
     return FALSE;
+  server->conns = silc_dlist_init();
+  if (!server->conns)
+    return FALSE;
+  server->expired_clients = silc_dlist_init();
+  if (!server->expired_clients)
+    return FALSE;
 
   *new_server = server;
 
@@ -456,8 +566,6 @@ void silc_server_free(SilcServer server)
 
   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)
@@ -512,21 +620,26 @@ void silc_server_free(SilcServer server)
   silc_idcache_free(server->global_list->channels);
   silc_hash_table_free(server->watcher_list);
   silc_hash_table_free(server->watcher_list_pk);
-
   silc_hash_free(server->md5hash);
   silc_hash_free(server->sha1hash);
-  silc_hmac_unregister_all();
-  silc_hash_unregister_all();
-  silc_cipher_unregister_all();
-  silc_pkcs_unregister_all();
+
+  silc_dlist_uninit(server->listeners);
+  silc_dlist_uninit(server->conns);
+  silc_dlist_uninit(server->expired_clients);
+  silc_skr_free(server->repository);
+  silc_packet_engine_stop(server->packet_engine);
 
   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);
+
+  silc_hmac_unregister_all();
+  silc_hash_unregister_all();
+  silc_cipher_unregister_all();
+  silc_pkcs_unregister_all();
 }
 
 /* Creates a new server listener. */
@@ -554,6 +667,7 @@ silc_server_listen(SilcServer server, const char *server_ip, SilcUInt16 port)
 
 SilcBool silc_server_init_secondary(SilcServer server)
 {
+  return TRUE;
 #if 0
   int sock = 0;
   SilcPacketStream newsocket = NULL;
@@ -680,9 +794,11 @@ SilcBool silc_server_init(SilcServer server)
     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);
+    silc_idcache_alloc(0, SILC_ID_SERVER, silc_idlist_server_destructor,
+                      server);
   server->local_list->channels =
-    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+    silc_idcache_alloc(0, SILC_ID_CHANNEL, silc_idlist_channel_destructor,
+                      NULL);
 
   /* These are allocated for normal server as well as these hold some
      global information that the server has fetched from its router. For
@@ -691,9 +807,11 @@ SilcBool silc_server_init(SilcServer server)
     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);
+    silc_idcache_alloc(0, SILC_ID_SERVER, silc_idlist_server_destructor,
+                      server);
   server->global_list->channels =
-    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+    silc_idcache_alloc(0, SILC_ID_CHANNEL, silc_idlist_channel_destructor,
+                      NULL);
 
   /* Init watcher lists */
   server->watcher_list =
@@ -709,15 +827,6 @@ SilcBool silc_server_init(SilcServer server)
   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;
-
   /* Create TCP listener */
   listener = silc_server_listen(
                   server,
@@ -730,25 +839,6 @@ SilcBool silc_server_init(SilcServer server)
 
   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
-
   /* Create a Server ID for the server. */
   port = silc_net_listener_get_port(listener, NULL);
   ip = silc_net_listener_get_ip(listener, NULL);
@@ -763,6 +853,8 @@ SilcBool silc_server_init(SilcServer server)
   server->id = id;
   server->server_name = server->config->server_info->server_name;
   server->config->server_info->server_name = NULL;
+  silc_id_id2str(server->id, SILC_ID_SERVER, server->id_string,
+                sizeof(server->id_string), &server->id_string_len);
 
   /* 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.
@@ -772,7 +864,7 @@ SilcBool silc_server_init(SilcServer server)
     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"));
+    SILC_LOG_ERROR(("Could not add local server to cache"));
     goto err;
   }
   id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
@@ -782,19 +874,10 @@ SilcBool silc_server_init(SilcServer server)
   if (silc_server_init_secondary(server) == FALSE)
     goto err;
 
-  /* Create connections to configured routers. */
-  silc_server_create_connections(server);
-
   server->listenning = TRUE;
 
-  /* 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;
+  /* Create connections to configured routers. */
+  silc_server_create_connections(server);
 
   /* If server connections has been configured then we must be router as
      normal server cannot have server connections, only router connections. */
@@ -846,6 +929,14 @@ SilcBool silc_server_init(SilcServer server)
   if (!server->packet_engine)
     goto err;
 
+  /* Register client entry expiration timeout */
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_purge_expired_clients, server,
+                                600, 0);
+
+  /* Initialize HTTP server */
+  silc_server_http_init(server);
+
   SILC_LOG_DEBUG(("Server initialized"));
 
   /* We are done here, return succesfully */
@@ -1120,6 +1211,7 @@ void silc_server_stop(SilcServer server)
 {
   SilcDList list;
   SilcPacketStream ps;
+  SilcNetListener listener;
 
   SILC_LOG_INFO(("SILC Server shutting down"));
 
@@ -1141,11 +1233,18 @@ void silc_server_stop(SilcServer server)
       silc_server_free_sock_user_data(server, ps,
                                      "Server is shutting down");
     }
+    silc_dlist_uninit(list);
   }
 
   /* We are not connected to network anymore */
   server->standalone = TRUE;
 
+  silc_dlist_start(server->listeners);
+  while ((listener = silc_dlist_get(server->listeners)))
+    silc_net_close_listener(listener);
+
+  silc_server_http_uninit(server);
+
   silc_schedule_stop(server->schedule);
   silc_schedule_uninit(server->schedule);
   server->schedule = NULL;
@@ -1153,110 +1252,33 @@ void silc_server_stop(SilcServer server)
   SILC_LOG_DEBUG(("Server stopped"));
 }
 
-#if 0
-/* Parses whole packet, received earlier. */
+/* Purge expired client entries from the server */
 
-SILC_TASK_CALLBACK(silc_server_packet_parse_real)
+SILC_TASK_CALLBACK(silc_server_purge_expired_clients)
 {
-  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;
-
-  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
-    SILC_LOG_DEBUG(("Connection is disconnected"));
-    goto out;
-  }
-
-  server->stat.packets_received++;
-
-  /* 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;
-  }
-
-  if (ret == SILC_PACKET_NONE) {
-    SILC_LOG_DEBUG(("Error parsing packet"));
-    goto out;
-  }
-
-  /* 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);
-    }
-  }
-
-  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;
-
-      /* 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;
-
-      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;
-      }
+  SilcServer server = context;
+  SilcClientEntry client;
+  SilcIDList id_list;
 
-      silc_server_packet_route(server, conn, packet);
-      silc_free(id);
-      goto out;
-    }
-  }
+  SILC_LOG_DEBUG(("Expire timeout"));
 
-  /* Parse the incoming packet type */
-  silc_server_packet_parse_type(server, sock, packet);
+  silc_dlist_start(server->expired_clients);
+  while ((client = silc_dlist_get(server->expired_clients))) {
+    if (client->data.status & SILC_IDLIST_STATUS_REGISTERED)
+      continue;
 
-  /* 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);
+    id_list = (client->data.status & SILC_IDLIST_STATUS_LOCAL ?
+              server->local_list : server->global_list);
 
-    /* If we have backup routers then we need to feed all broadcast
-       data to those servers. */
-    silc_server_backup_broadcast(server, sock, packet);
+    silc_idlist_del_data(client);
+    silc_idlist_del_client(id_list, client);
+    silc_dlist_del(server->expired_clients, client);
   }
 
- out:
-  silc_packet_context_free(packet);
-  silc_free(parse_ctx);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_purge_expired_clients, server,
+                                600, 0);
 }
-#endif /* 0 */
 
 
 /******************************* Connecting *********************************/
@@ -1615,7 +1637,7 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   server->stat.conn_num++;
 
   /* Set source ID to packet stream */
-  if (!silc_packet_set_ids(sconn->sock, SILC_ID_SERVER, &server->id,
+  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);
@@ -1989,9 +2011,16 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
 {
   SilcPacketStream sock = context;
   SilcUnknownEntry entry = silc_packet_get_context(sock);
+  SilcIDListData idata = (SilcIDListData)entry;
   SilcServer server = entry->server;
-  SilcServerConfigConnParams *param;
+  SilcServerConfigConnParams *param = &server->config->param;
+  SilcServerConnection sconn;
   void *id_entry;
+  const char *hostname;
+  SilcUInt16 port;
+
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, NULL, &port);
 
   if (success == FALSE) {
     /* Authentication failed */
@@ -2091,12 +2120,12 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
          client->mode |= SILC_UMODE_ANONYMOUS;
       }
 
-      /* 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);
+      /* Add public key to repository */
+      if (!silc_server_get_public_key_by_client(server, client, NULL))
+       silc_skr_add_public_key_simple(server->repository,
+                                      entry->data.public_key,
+                                      SILC_SKR_USAGE_IDENTIFICATION, client,
+                                      NULL);
 
       id_entry = (void *)client;
       break;
@@ -2312,6 +2341,17 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
     break;
   }
 
+  /* Add connection to server->conns so that we know we have connection
+     to this peer. */
+  sconn = silc_calloc(1, sizeof(*sconn));
+  sconn->server = server;
+  sconn->sock = sock;
+  sconn->remote_host = strdup(hostname);
+  sconn->remote_port = port;
+  silc_dlist_add(server->conns, sconn);
+  idata->sconn = sconn;
+  idata->last_receive = time(NULL);
+
   /* Add the common data structure to the ID entry. */
   silc_idlist_add_data(id_entry, (SilcIDListData)entry);
   silc_packet_set_context(sock, id_entry);
@@ -2319,23 +2359,19 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
   /* Connection has been fully established now. Everything is ok. */
   SILC_LOG_DEBUG(("New connection authenticated"));
 
-  /* XXX Add connection to server->conns so that we know we have connection
-     to this peer. */
-  /* XXX */
-
 #if 0
   /* Perform keepalive. */
   if (param->keepalive_secs)
     silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
                              silc_server_perform_heartbeat,
                              server->schedule);
+#endif
 
   /* 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
+    silc_socket_stream_set_qos(silc_packet_stream_get_stream(sock),
+                              param->qos_rate_limit, param->qos_bytes_limit,
+                              param->qos_limit_sec, param->qos_limit_usec);
 
   silc_server_config_unref(&entry->cconfig);
   silc_server_config_unref(&entry->sconfig);
@@ -2358,6 +2394,7 @@ silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status,
 {
   SilcPacketStream sock = context;
   SilcUnknownEntry entry = silc_packet_get_context(sock);
+  SilcIDListData idata = (SilcIDListData)entry;
   SilcServer server = entry->server;
   SilcConnAuth connauth;
   SilcCipher send_key, receive_key;
@@ -2388,6 +2425,9 @@ silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status,
   silc_packet_set_keys(sock, send_key, receive_key, hmac_send,
                       hmac_receive, FALSE);
 
+  idata->rekey = rekey;
+  idata->public_key = silc_pkcs_public_key_copy(prop->public_key);
+
   SILC_LOG_DEBUG(("Starting connection authentication"));
   server->stat.auth_attempts++;
 
@@ -2428,15 +2468,13 @@ static void silc_server_accept_new_connection(SilcNetStatus status,
 
   /* Check for maximum allowed connections */
   server->stat.conn_attempts++;
-#if 0
-  if (silc_server_num_connections(server) >
+  if (silc_dlist_count(server->conns) >
       server->config->param.connections_max) {
     SILC_LOG_ERROR(("Refusing connection, server is full"));
     server->stat.conn_failures++;
     silc_stream_destroy(stream);
     return;
   }
-#endif
 
   /* Get hostname, IP and port */
   if (!silc_socket_stream_get_info(stream, NULL, (const char **)&hostname,
@@ -2459,7 +2497,7 @@ static void silc_server_accept_new_connection(SilcNetStatus status,
   server->stat.conn_num++;
 
   /* Set source ID to packet stream */
-  if (!silc_packet_set_ids(packet_stream, SILC_ID_SERVER, &server->id,
+  if (!silc_packet_set_ids(packet_stream, SILC_ID_SERVER, server->id,
                           0, NULL)) {
     /* Out of memory */
     server->stat.conn_failures++;
@@ -2622,6 +2660,62 @@ SILC_TASK_CALLBACK(silc_server_do_rekey)
   idata->sconn->op = silc_ske_rekey_initiator(ske, sock, idata->rekey);
 }
 
+/* Responder rekey completion callback */
+
+static void
+silc_server_rekey_resp_completion(SilcSKE ske,
+                                 SilcSKEStatus status,
+                                 const SilcSKESecurityProperties prop,
+                                 const SilcSKEKeyMaterial keymat,
+                                 SilcSKERekeyMaterial rekey,
+                                 void *context)
+{
+  SilcPacketStream sock = context;
+  SilcIDListData idata = silc_packet_get_context(sock);
+
+  idata->sconn->op = NULL;
+  if (status != SILC_SKE_STATUS_OK) {
+    SILC_LOG_ERROR(("Error during rekey protocol with %s",
+                   idata->sconn->remote_host));
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Rekey protocol completed with %s:%d [%s]",
+                 idata->sconn->remote_host, idata->sconn->remote_port,
+                 SILC_CONNTYPE_STRING(idata->conn_type)));
+
+  /* Save rekey data for next rekey */
+  idata->rekey = rekey;
+}
+
+/* Start rekey as responder */
+
+static void silc_server_rekey(SilcServer server, SilcPacketStream sock,
+                             SilcPacket packet)
+{
+  SilcIDListData idata = silc_packet_get_context(sock);
+  SilcSKE ske;
+
+  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) {
+    silc_packet_free(packet);
+    return;
+  }
+
+  /* Set SKE callbacks */
+  silc_ske_set_callbacks(ske, NULL, silc_server_rekey_resp_completion, sock);
+
+  /* Perform rekey */
+  idata->sconn->op = silc_ske_rekey_responder(ske, sock, idata->rekey,
+                                             packet);
+}
+
 
 /****************************** Disconnection *******************************/
 
@@ -2658,9 +2752,10 @@ void silc_server_close_connection(SilcServer server,
 
   memset(tmp, 0, sizeof(tmp));
   //  silc_socket_get_error(sock, tmp, sizeof(tmp));
-  silc_socket_stream_get_info(sock, NULL, &hostname, NULL, &port);
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, NULL, &port);
   SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", hostname, port,
-                SILC_CONNTYPE_STRING(idata->conn_type),
+                idata ? SILC_CONNTYPE_STRING(idata->conn_type) : "",
                 tmp[0] ? tmp : ""));
 
   //  silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
@@ -2748,10 +2843,12 @@ void silc_server_free_client_data(SilcServer server,
   /* Remove this client from watcher list if it is */
   silc_server_del_from_watcher_list(server, client);
 
-  /* Remove this client from the public key hash list */
-  if (client->data.public_key)
-    silc_hash_table_del_by_context(server->pk_hash,
-                                   client->data.public_key, client);
+  /* Remove client's public key from repository, this will free it too. */
+  if (client->data.public_key) {
+    silc_skr_del_public_key(server->repository, client->data.public_key,
+                           client);
+    client->data.public_key = NULL;
+  }
 
   /* Update statistics */
   server->stat.my_clients--;
@@ -2800,6 +2897,7 @@ void silc_server_free_sock_user_data(SilcServer server,
       SilcClientEntry client_entry = (SilcClientEntry)idata;
       silc_server_free_client_data(server, sock, client_entry, TRUE,
                                   signoff_message);
+      silc_packet_set_context(sock, NULL);
       break;
     }
 
@@ -2989,6 +3087,8 @@ void silc_server_free_sock_user_data(SilcServer server,
        silc_server_announce_channels(server, time(0) - 300,
                                      backup_router->connection);
       }
+
+      silc_packet_set_context(sock, NULL);
       break;
     }
 
@@ -3000,6 +3100,7 @@ void silc_server_free_sock_user_data(SilcServer server,
 
       silc_idlist_del_data(idata);
       silc_free(entry);
+      silc_packet_set_context(sock, NULL);
       break;
     }
   }
@@ -3221,48 +3322,6 @@ SilcBool silc_server_remove_from_one_channel(SilcServer server,
   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. */
-
-SILC_TASK_CALLBACK(silc_server_timeout_remote)
-{
-  SilcServer server = (SilcServer)context;
-  SilcPacketStream sock = server->sockets[fd];
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (!sock)
-    return;
-
-  SILC_LOG_ERROR(("No response from %s (%s), Connection timeout",
-                 sock->hostname, sock->ip));
-
-  /* If we have protocol active we must assure that we call the protocol's
-     final callback so that all the memory is freed. */
-  if (sock->protocol && sock->protocol->protocol &&
-      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
-    protocol = sock->protocol->protocol->type;
-    silc_protocol_cancel(sock->protocol, server->schedule);
-    sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute_final(sock->protocol, server->schedule);
-    sock->protocol = NULL;
-    return;
-  }
-
-  silc_server_disconnect_remote(server, sock,
-                               protocol ==
-                               SILC_PROTOCOL_SERVER_CONNECTION_AUTH ?
-                               SILC_STATUS_ERR_AUTH_FAILED :
-                               SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
-                               "Connection timeout");
-
-  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
    are created by routers thus this function is never used by normal
@@ -4716,7 +4775,7 @@ silc_server_get_client_route(SilcServer server,
 
   /* Decode destination Client ID */
   if (!client_id) {
-    if (!silc_id_str2id(id_data, id_len, SILC_ID_CHANNEL, &clid, sizeof(clid)))
+    if (!silc_id_str2id(id_data, id_len, SILC_ID_CLIENT, &clid, sizeof(clid)))
       return NULL;
     id = silc_id_dup(&clid, SILC_ID_CLIENT);
   } else {