updates.
[silc.git] / apps / silcd / server.c
index 5a0a9ebd5d39e778ae0e7a237fe73a2679d246f4..bb633a65ecd6c4839e404b2f6153dd013f1450c4 100644 (file)
@@ -44,6 +44,7 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote);
 SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
 SILC_TASK_CALLBACK(silc_server_failure_callback);
 SILC_TASK_CALLBACK(silc_server_rekey_callback);
+SILC_TASK_CALLBACK(silc_server_get_stats);
 
 /* 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
@@ -148,6 +149,8 @@ bool silc_server_init(SilcServer server)
 
   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);
@@ -338,12 +341,20 @@ bool silc_server_init(SilcServer server)
                         (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
+  /* If we are normal server we'll retrieve network statisticial information
+     once in a while from the router. */
+  if (server->server_type == SILC_SERVER)
+    silc_schedule_task_add(purge->schedule, 0, silc_server_get_stats,
+                          server, 10, 0, SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
+
   SILC_LOG_DEBUG(("Server initialized"));
 
   /* We are done here, return succesfully */
   return TRUE;
 
  err:
+  silc_server_config_unref(&server->config_ref);
   silc_net_close_server(sock);
   return FALSE;
 }
@@ -356,7 +367,6 @@ bool silc_server_init(SilcServer server)
 bool silc_server_rehash(SilcServer server)
 {
   SilcServerConfig newconfig;
-  SilcUInt32 max_conns;
 
   SILC_LOG_INFO(("Rehashing server"));
 
@@ -371,22 +381,11 @@ bool silc_server_rehash(SilcServer server)
     return FALSE;
   }
 
-  max_conns = server->config->param.connections_max;
-
-  /* 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);
-
-  /* Take new config context */
-  server->config = newconfig;
-  silc_server_config_ref(&server->config_ref, server->config, server->config);
-
   /* Reinit scheduler if necessary */
-  if (server->config->param.connections_max > max_conns)
-    silc_schedule_reinit(server->schedule, 
-                        server->config->param.connections_max);
+  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)) {
@@ -397,12 +396,16 @@ bool silc_server_rehash(SilcServer server)
     /* Update the idcache list with a fresh pointer */
     silc_free(server->id_entry->server_name);
     server->id_entry->server_name = strdup(server->server_name);
-    silc_idcache_del_by_context(server->local_list->servers, server->id_entry);
-    silc_idcache_add(server->local_list->servers,
-                    server->id_entry->server_name,
-                    server->id_entry->id, server->id_entry, 0, NULL);
+    if (!silc_idcache_del_by_context(server->local_list->servers, 
+                                    server->id_entry))
+      return FALSE;
+    if (!silc_idcache_add(server->local_list->servers,
+                         server->id_entry->server_name,
+                         server->id_entry->id, server->id_entry, 0, NULL))
+      return FALSE;
   }
 
+  /* Set logging */
   silc_server_config_setlogfiles(server);
 
   /* Change new key pair if necessary */
@@ -411,10 +414,10 @@ bool silc_server_rehash(SilcServer server)
                                    newconfig->server_info->public_key)) {
     silc_pkcs_public_key_free(server->public_key);
     silc_pkcs_private_key_free(server->private_key);
-    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;
+    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);
@@ -432,8 +435,8 @@ bool silc_server_rehash(SilcServer server)
                         SILC_TASK_PRI_NORMAL);
 
   /* Check whether our router status has changed */
-  if (server->config->servers) {
-    SilcServerConfigServer *ptr = server->config->servers;
+  if (newconfig->servers) {
+    SilcServerConfigServer *ptr = newconfig->servers;
 
     server->server_type = SILC_ROUTER;
     while (ptr) {
@@ -447,6 +450,16 @@ bool silc_server_rehash(SilcServer server)
     }
   }
 
+  /* 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);
+
+  /* Take new config context */
+  server->config = newconfig;
+  silc_server_config_ref(&server->config_ref, server->config, server->config);
+
   SILC_LOG_DEBUG(("Server rehashed"));
 
   return TRUE;
@@ -686,6 +699,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
     return;
   }
 
+  /* 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) {
 
@@ -1416,8 +1435,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* Statistics */
       server->stat.my_clients++;
       server->stat.clients++;
-      if (server->server_type == SILC_ROUTER)
-       server->stat.cell_clients++;
+      server->stat.cell_clients++;
 
       /* Get connection parameters */
       if (conn->param) {
@@ -2317,6 +2335,14 @@ void silc_server_packet_parse_type(SilcServer server,
     silc_server_ftp(server, sock, packet);
     break;
 
+  case SILC_PACKET_RESUME_CLIENT:
+    /* Resume client */
+    SILC_LOG_DEBUG(("Resume Client packet"));
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_resume_client(server, sock, packet);
+    break;
+
   case SILC_PACKET_RESUME_ROUTER:
     /* Resume router packet received. This packet is received for backup
        router resuming protocol. */
@@ -2483,7 +2509,7 @@ void silc_server_free_client_data(SilcServer server,
   /* Update statistics */
   server->stat.my_clients--;
   server->stat.clients--;
-  if (server->server_type == SILC_ROUTER)
+  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);
@@ -2497,9 +2523,9 @@ void silc_server_free_client_data(SilcServer server,
                         (void *)i, 300, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
   client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+  client->mode = 0;
   client->router = NULL;
   client->connection = NULL;
-  client->mode = 0;
 }
 
 /* Frees user_data pointer from socket connection object. This also sends
@@ -3943,17 +3969,22 @@ void silc_server_save_users_on_channel(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 silc_server_get_client_route(SilcServer server,
-                                                 unsigned char *id_data,
-                                                 SilcUInt32 id_len,
-                                                 SilcClientID *client_id,
-                                                 SilcIDListData *idata)
+SilcSocketConnection
+silc_server_get_client_route(SilcServer server,
+                            unsigned char *id_data,
+                            SilcUInt32 id_len,
+                            SilcClientID *client_id,
+                            SilcIDListData *idata,
+                            SilcClientEntry *client_entry)
 {
   SilcClientID *id;
   SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
 
+  if (client_entry)
+    *client_entry = NULL;
+
   /* Decode destination Client ID */
   if (!client_id) {
     id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
@@ -3985,6 +4016,8 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server,
     /* Seems that client really is directly connected to us */
     if (idata)
       *idata = (SilcIDListData)client;
+    if (client_entry)
+      *client_entry = client;
     return client->connection;
   }
 
@@ -4198,3 +4231,30 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     silc_ske_free(ctx->ske);
   silc_free(ctx);
 }
+
+/* Task callback used to retrieve network statistical information from
+   router server once in a while. */
+
+SILC_TASK_CALLBACK(silc_server_get_stats)
+{
+  SilcServer server = (SilcServer)context;
+  SilcBuffer idp, packet;
+
+  SILC_LOG_DEBUG(("Retrieving stats from router"));
+
+  if (!server->standalone) {
+    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);
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_COMMAND, 0, packet->data,
+                           packet->len, FALSE);
+    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);
+}