Remove possible packet error timeouts in EOS callback
[silc.git] / apps / silcd / server.c
index 05deee4b61613878979e263954dff52bc3c73eee..eb8aed23f7f98719e11df33c22a5d93d6ea83a81 100644 (file)
@@ -27,6 +27,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
 SILC_TASK_CALLBACK(silc_server_do_rekey);
 SILC_TASK_CALLBACK(silc_server_purge_expired_clients);
+SILC_TASK_CALLBACK(silc_server_packet_error_timeout);
 static void silc_server_accept_new_connection(SilcNetStatus status,
                                              SilcStream stream,
                                              void *context);
@@ -199,6 +200,10 @@ static void silc_server_packet_eos(SilcPacketEngine engine,
   if (!idata)
     return;
 
+  /* Remove any possible pending packet error timeout */
+  silc_schedule_task_del_by_all(server->schedule, 0,
+                               silc_server_packet_error_timeout, stream);
+
   if (server->router_conn && server->router_conn->sock == stream &&
       !server->router && server->standalone) {
     if (idata->sconn && idata->sconn->callback)
@@ -233,7 +238,10 @@ SILC_TASK_CALLBACK(silc_server_packet_error_timeout)
 
   if (server->router_conn && server->router_conn->sock == stream &&
       !server->router && server->standalone) {
+    if (idata->sconn && idata->sconn->callback)
+      (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
     silc_server_create_connections(server);
+    silc_server_free_sock_user_data(server, stream, NULL);
   } else {
     /* If backup disconnected then mark that resuming will not be allowed */
      if (server->server_type == SILC_ROUTER && !server->backup_router &&
@@ -280,9 +288,14 @@ static void silc_server_packet_error(SilcPacketEngine engine,
   if (!silc_packet_stream_is_valid(stream))
     return;
 
+  /* In case we get here many times, register only one timeout */
+  silc_schedule_task_del_by_all(server->schedule, 0,
+                               silc_server_packet_error_timeout, stream);
+
+  /* Close connection with random timeout */
   silc_schedule_task_add_timeout(server->schedule,
-                                silc_server_packet_error_timeout,
-                                stream, 0, 0);
+                                silc_server_packet_error_timeout, stream,
+                                silc_rng_get_byte(server->rng) % 10, 0);
 }
 
 /* Packet stream callbacks */
@@ -767,7 +780,6 @@ SilcBool silc_server_init(SilcServer server)
   SilcNetListener listener;
   SilcUInt16 *port;
   char **ip;
-  char *external_ip;
 
   SILC_LOG_DEBUG(("Initializing server"));
 
@@ -871,11 +883,8 @@ SilcBool silc_server_init(SilcServer server)
   /* Create a Server ID for the server. */
   port = silc_net_listener_get_port(listener, NULL);
   ip = silc_net_listener_get_ip(listener, NULL);
-  external_ip = server->config->server_info->external_ip ?
-               server->config->server_info->external_ip :
-               server->config->server_info->primary->public_ip;
-  silc_id_create_server_id(external_ip ?
-                          external_ip :
+  silc_id_create_server_id(server->config->server_info->primary->public_ip ?
+                          server->config->server_info->primary->public_ip :
                           ip[0], port[0], server->rng, &id);
   if (!id)
     goto err;
@@ -1802,6 +1811,8 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   }
   entry->server = server;
   entry->data.sconn = sconn;
+  entry->data.conn_type = SILC_CONN_UNKNOWN;
+  entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
   silc_packet_set_context(sconn->sock, entry);
 
   SILC_LOG_DEBUG(("Created unknown connection %p", entry));
@@ -2339,6 +2350,8 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
       entry->data.conn_type = SILC_CONN_CLIENT;
 
       /* Statistics */
+      SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                     server->stat.clients + 1));
       server->stat.my_clients++;
       server->stat.clients++;
       server->stat.cell_clients++;
@@ -2905,6 +2918,18 @@ static void silc_server_rekey_completion(SilcSKE ske,
                                 sock, idata->sconn->rekey_timeout, 0);
 }
 
+/* Helper to stop future rekeys on a link. */
+void silc_server_stop_rekey(SilcServer server, SilcClientEntry client)
+{
+  if (!client->connection)
+    return;
+
+  SILC_LOG_DEBUG(("Stopping rekey for client %p", client));
+
+  silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_rekey,
+                               client->connection);
+}
+
 /* Rekey callback.  Start rekey as initiator */
 
 SILC_TASK_CALLBACK(silc_server_do_rekey)
@@ -3132,7 +3157,13 @@ void silc_server_free_client_data(SilcServer server,
   }
 
   /* Update statistics */
-  server->stat.my_clients--;
+
+  /* Local detached clients aren't counted. */
+  if (!client->local_detached)
+    server->stat.my_clients--;
+  SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                 server->stat.clients - 1));
+  SILC_VERIFY(server->stat.clients > 0);
   server->stat.clients--;
   if (server->stat.cell_clients)
     server->stat.cell_clients--;
@@ -3185,19 +3216,24 @@ void silc_server_free_sock_user_data(SilcServer server,
   if (!idata)
     return;
 
+  /* Remove any possible pending timeout */
   silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_rekey,
                                sock);
+  silc_schedule_task_del_by_all(server->schedule, 0,
+                               silc_server_packet_error_timeout, sock);
 
   /* Cancel active protocols */
   if (idata) {
     if (idata->sconn && idata->sconn->op) {
       SILC_LOG_DEBUG(("Abort active protocol"));
       silc_async_abort(idata->sconn->op, NULL, NULL);
+      idata->sconn->op = NULL;
     }
     if (idata->conn_type == SILC_CONN_UNKNOWN &&
         ((SilcUnknownEntry)idata)->op) {
       SILC_LOG_DEBUG(("Abort active protocol"));
       silc_async_abort(((SilcUnknownEntry)idata)->op, NULL, NULL);
+      idata->sconn->op = NULL;
     }
   }
 
@@ -5011,7 +5047,7 @@ void silc_server_save_users_on_channel(SilcServer server,
     }
 
     if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-      SILC_LOG_ERROR(("Attempting to add unregistered client to channel ",
+      SILC_LOG_ERROR(("Attempting to add unregistered client to channel "
                      "%s", channel->channel_name));
       continue;
     }