updates
[silc.git] / apps / silcd / server.c
index 24f71ef5b8190a323a9af2dcceebd16f98485de5..b3914316e3b9cedef4d11937049dcc429a3d323a 100644 (file)
@@ -163,9 +163,6 @@ int silc_server_init(SilcServer server)
   silc_hash_alloc("md5", &server->md5hash);
   silc_hash_alloc("sha1", &server->sha1hash);
 
-  /* Initialize none cipher */
-  silc_cipher_alloc("none", &server->none_cipher);
-
   /* Allocate PKCS context for local public and private keys */
   silc_pkcs_alloc(server->public_key->name, &server->pkcs);
   silc_pkcs_public_key_set(server->pkcs, server->public_key);
@@ -504,6 +501,7 @@ void silc_server_stop(SilcServer server)
   if (server->schedule) {
     silc_schedule_stop(server->schedule);
     silc_schedule_uninit(server->schedule);
+    server->schedule = NULL;
   }
 
   silc_server_protocols_unregister();
@@ -524,6 +522,10 @@ void silc_server_start_key_exchange(SilcServer server,
   SilcServerKEInternalContext *proto_ctx;
   void *context;
 
+  /* Cancel any possible retry timeouts */
+  silc_schedule_task_del_by_callback(server->schedule,
+                                    silc_server_connect_router);
+
   /* Set socket options */
   silc_net_set_socket_nonblock(sock);
   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
@@ -637,11 +639,13 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
                                    sconn->remote_port, 
                                    sconn->remote_host);
   if (sock < 0) {
-    SILC_LOG_ERROR(("Could not connect to router"));
-    silc_schedule_task_add(server->schedule, fd, 
-                          silc_server_connect_to_router_retry,
-                          context, 0, 1, SILC_TASK_TIMEOUT, 
-                          SILC_TASK_PRI_NORMAL);
+    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, fd, 
+                            silc_server_connect_to_router_retry,
+                            context, 0, 1, SILC_TASK_TIMEOUT, 
+                            SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -945,7 +949,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
      timeout!! */
   hb_context = silc_calloc(1, sizeof(*hb_context));
   hb_context->server = server;
-  silc_socket_set_heartbeat(sock, 600, hb_context,
+  silc_socket_set_heartbeat(sock, 300, hb_context,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
@@ -1292,7 +1296,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SilcSocketConnection sock = ctx->sock;
   SilcServerHBContext hb_context;
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
-  void *id_entry = NULL;
+  void *id_entry;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1434,15 +1438,15 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       break;
     }
   default:
+    goto out;
     break;
   }
 
   sock->type = ctx->conn_type;
 
   /* Add the common data structure to the ID entry. */
-  if (id_entry)
-    silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
-      
+  silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
+
   /* Add to sockets internal pointer for fast referencing */
   silc_free(sock->user_data);
   sock->user_data = id_entry;
@@ -1455,7 +1459,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
      timeout!! */
   hb_context = silc_calloc(1, sizeof(*hb_context));
   hb_context->server = server;
-  silc_socket_set_heartbeat(sock, 600, hb_context,
+  silc_socket_set_heartbeat(sock, 400, hb_context,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
@@ -1563,9 +1567,13 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
     SILC_SET_DISCONNECTING(sock);
 
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
-    else if (server->router_conn && server->router_conn->sock == sock &&
+    if (sock->user_data) {
+      char tmp[128];
+      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_schedule_task_add(server->schedule, 0, 
                             silc_server_connect_to_router, 
@@ -2204,7 +2212,7 @@ void silc_server_packet_parse_type(SilcServer server,
 /* Creates connection to a remote router. */
 
 void silc_server_create_connection(SilcServer server,
-                                  char *remote_host, uint32 port)
+                                  const char *remote_host, uint32 port)
 {
   SilcServerConnection sconn;
 
@@ -2213,6 +2221,7 @@ void silc_server_create_connection(SilcServer server,
   sconn->server = server;
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
+  sconn->no_reconnect = TRUE;
 
   silc_schedule_task_add(server->schedule, 0, 
                         silc_server_connect_router,
@@ -2346,6 +2355,14 @@ void silc_server_free_client_data(SilcServer server,
     silc_server_remove_from_channels(server, NULL, client, 
                                     FALSE, NULL, FALSE);
     
+  /* Update statistics */
+  server->stat.my_clients--;
+  server->stat.clients--;
+  if (server->server_type == SILC_ROUTER)
+    server->stat.cell_clients--;
+  SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+  SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
   /* We will not delete the client entry right away. We will take it
      into history (for WHOWAS command) for 5 minutes */
   i->server = server;
@@ -2357,12 +2374,7 @@ void silc_server_free_client_data(SilcServer server,
   client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
   client->router = NULL;
   client->connection = NULL;
-
-  /* Free the client entry and everything in it */
-  server->stat.my_clients--;
-  server->stat.clients--;
-  if (server->server_type == SILC_ROUTER)
-    server->stat.cell_clients--;
+  client->mode = 0;
 }
 
 /* Frees user_data pointer from socket connection object. This also sends
@@ -2800,7 +2812,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
 
   channel_name = strdup(channel_name);
 
-  /* Create the channel */
+  /* Create the channel ID */
   if (!silc_id_create_channel_id(server, router_id, server->rng, 
                                 &channel_id)) {
     silc_free(channel_name);
@@ -2808,6 +2820,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
     silc_hmac_free(newhmac);
     return NULL;
   }
+
+  /* Create the channel */
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
                                  NULL, key, newhmac, 0);
@@ -2815,6 +2829,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
     silc_free(channel_name);
     silc_cipher_free(key);
     silc_hmac_free(newhmac);
+    silc_free(channel_id);
     return NULL;
   }
 
@@ -2824,11 +2839,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_free(channel_name);
-    silc_cipher_free(key);
-    silc_hmac_free(newhmac);
-    silc_free(entry->cipher);
-    silc_free(entry->hmac_name);
+    silc_idlist_del_channel(server->local_list, entry);
     return NULL;
   }
 
@@ -2883,6 +2894,8 @@ silc_server_create_new_channel_with_id(SilcServer server,
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
                                  NULL, key, newhmac, 0);
   if (!entry) {
+    silc_cipher_free(key);
+    silc_hmac_free(newhmac);
     silc_free(channel_name);
     return NULL;
   }
@@ -2890,7 +2903,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_free(channel_name);
+    silc_idlist_del_channel(server->local_list, entry);
     return NULL;
   }
 
@@ -3017,7 +3030,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   /* Decode channel key payload */
-  payload = silc_channel_key_payload_parse(key_payload->data,
+  payload = silc_channel_key_payload_parse(key_payload->data, 
                                           key_payload->len);
   if (!payload) {
     SILC_LOG_ERROR(("Bad channel key payload received, dropped"));
@@ -3040,7 +3053,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     if (!channel) {
       channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
       if (!channel) {
-       SILC_LOG_ERROR(("Received key for non-existent channel"));
+       SILC_LOG_ERROR(("Received key for non-existent channel %s",
+                       silc_id_render(id, SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -3125,8 +3139,7 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
 {
   SilcServerHBContext hb = (SilcServerHBContext)hb_context;
 
-  SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname,
-                 sock->ip));
+  SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip));
 
   /* Send the heartbeat */
   silc_server_send_heartbeat(hb->server, sock);
@@ -3582,6 +3595,8 @@ void silc_server_announce_channels(SilcServer server,
     int i;
 
     for (i = 0; i < channel_users_modes_c; i++) {
+      if (!channel_users_modes[i])
+        continue;
       silc_buffer_push(channel_users_modes[i], 
                       channel_users_modes[i]->data - 
                       channel_users_modes[i]->head);
@@ -3710,6 +3725,8 @@ void silc_server_save_users_on_channel(SilcServer server,
   SilcIDCacheEntry cache;
   bool global;
 
+  SILC_LOG_DEBUG(("Start"));
+
   for (i = 0; i < user_count; i++) {
     /* Client ID */
     SILC_GET16_MSB(idp_len, user_list->data + 2);
@@ -3915,10 +3932,14 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
    it using WHOIS command. */
 
 SilcClientEntry silc_server_get_client_resolve(SilcServer server,
-                                              SilcClientID *client_id)
+                                              SilcClientID *client_id,
+                                              bool *resolved)
 {
   SilcClientEntry client;
 
+  if (resolved)
+    *resolved = FALSE;
+
   client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (!client) {
@@ -3948,6 +3969,10 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
                            buffer->data, buffer->len, FALSE);
     silc_buffer_free(idp);
     silc_buffer_free(buffer);
+
+    if (resolved)
+      *resolved = TRUE;
+
     return NULL;
   }