Fixed more backup router reconnecting problems
[silc.git] / apps / silcd / server.c
index 73f363613f1a24ae59237900b29a411248142b12..52bc4b702779e89c6caf873c2cfa3e9cce345fc6 100644 (file)
@@ -201,6 +201,8 @@ static void silc_server_packet_eos(SilcPacketEngine engine,
 
   if (server->router_conn && server->router_conn->sock == stream &&
       !server->router && server->standalone) {
+    if (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 {
@@ -212,6 +214,8 @@ static void silc_server_packet_eos(SilcPacketEngine engine,
         server->backup_closed = TRUE;
     }
 
+    if (idata->sconn->callback)
+      (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
     silc_server_free_sock_user_data(server, stream, NULL);
   }
 
@@ -239,6 +243,8 @@ SILC_TASK_CALLBACK(silc_server_packet_error_timeout)
         server->backup_closed = TRUE;
     }
 
+    if (idata->sconn->callback)
+      (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
     silc_server_free_sock_user_data(server, stream, NULL);
   }
 
@@ -1263,13 +1269,10 @@ SILC_TASK_CALLBACK(silc_server_purge_expired_clients)
 
   silc_dlist_start(server->expired_clients);
   while ((client = silc_dlist_get(server->expired_clients))) {
-    if (client->data.status & SILC_IDLIST_STATUS_REGISTERED)
-      continue;
-
     /* For unregistered clients the created timestamp is actually
        unregistered timestamp.  Make sure client remains in history
        at least 500 seconds. */
-    if (curtime - client->data.created < 500)
+    if (client->data.created && curtime - client->data.created < 500)
       continue;
 
     id_list = (client->data.status & SILC_IDLIST_STATUS_LOCAL ?
@@ -1325,7 +1328,8 @@ void silc_server_create_connection(SilcServer server,
   sconn->no_conf = dynamic;
   sconn->server = server;
 
-  SILC_LOG_DEBUG(("Created connection %p", sconn));
+  SILC_LOG_DEBUG(("Created connection %p to %s:%d", sconn,
+                 remote_host, port));
 
   silc_schedule_task_add_timeout(server->schedule, silc_server_connect_router,
                                 sconn, 0, 0);
@@ -1356,7 +1360,15 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
 
   if (success == FALSE) {
     /* Authentication failed */
-    /* XXX retry connecting */
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
 
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
@@ -1451,6 +1463,15 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
                                                  SILC_ID_SERVER),
                                      NULL, sconn->sock);
     if (!id_entry) {
+      /* Try reconnecting if configuration wants it */
+      if (!sconn->no_reconnect) {
+        silc_schedule_task_add_timeout(server->schedule,
+                                      silc_server_connect_to_router_retry,
+                                      sconn, 1, 0);
+        silc_dlist_del(server->conns, sconn);
+        return;
+      }
+
       if (sconn->callback)
        (*sconn->callback)(server, NULL, sconn->callback_context);
       silc_server_free_sock_user_data(server, sconn->sock, NULL);
@@ -1465,6 +1486,7 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
     idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
                      SILC_IDLIST_STATUS_LOCAL);
     idata->sconn = sconn;
+    idata->sconn->callback = NULL;
 
     /* Statistics */
     server->stat.my_routers++;
@@ -1509,8 +1531,9 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
          silc_server_backup_add(server, server->id_entry, ip,
                                 sconn->remote_port, TRUE);
        }
+      }
 #if 0
-      } else {
+         else {
        /* We already have primary router.  Disconnect this connection */
        SILC_LOG_DEBUG(("We already have primary router, disconnect"));
        silc_idlist_del_server(server->global_list, id_entry);
@@ -1520,8 +1543,8 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success,
        silc_server_disconnect_remote(server, sconn->sock,
                                      SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
        return;
-#endif /* 0 */
       }
+#endif /* 0 */
     } else {
       /* Add this server to be our backup router */
       id_entry->server_type = SILC_BACKUP_ROUTER;
@@ -1595,9 +1618,17 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
     /* 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);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
@@ -1611,11 +1642,18 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
   /* 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)) {
+    silc_ske_free(ske);
 
-    /* XXX retry connecting */
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
 
     /* Error setting keys */
-    silc_ske_free(ske);
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
@@ -1631,10 +1669,18 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status,
   connauth = silc_connauth_alloc(server->schedule, ske,
                                 server->config->conn_auth_timeout);
   if (!connauth) {
-    /* XXX retry connecting */
+    silc_ske_free(ske);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
 
     /** Error allocating auth protocol */
-    silc_ske_free(ske);
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_free_sock_user_data(server, sconn->sock, NULL);
@@ -1691,6 +1737,16 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   if (!sconn->sock) {
     SILC_LOG_ERROR(("Cannot connect: cannot create packet stream"));
     silc_stream_destroy(sconn->stream);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
@@ -1701,9 +1757,19 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   /* 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);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
-    silc_packet_stream_destroy(sconn->sock);
     silc_server_connection_free(sconn);
     return;
   }
@@ -1712,6 +1778,18 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   entry = silc_calloc(1, sizeof(*entry));
   if (!entry) {
     silc_packet_stream_destroy(sconn->sock);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
+    if (sconn->callback)
+      (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
     return;
   }
@@ -1734,9 +1812,19 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
                       server->public_key, server->private_key, sconn);
   if (!ske) {
     silc_free(entry);
+    silc_packet_stream_destroy(sconn->sock);
+
+    /* Try reconnecting if configuration wants it */
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+      return;
+    }
+
     if (sconn->callback)
       (*sconn->callback)(server, NULL, sconn->callback_context);
-    silc_packet_stream_destroy(sconn->sock);
     silc_server_connection_free(sconn);
     return;
   }
@@ -1779,7 +1867,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 
   /* If we've reached max retry count, give up. */
   if ((sconn->retry_count > param->reconnect_count) &&
-      !param->reconnect_keep_trying) {
+      sconn->no_reconnect) {
     SILC_LOG_ERROR(("Could not connect, giving up"));
 
     if (sconn->callback)
@@ -1826,10 +1914,16 @@ static void silc_server_connection_established(SilcNetStatus status,
     SILC_LOG_ERROR(("Could not connect to %s:%d: %s",
                    sconn->remote_host, sconn->remote_port,
                    silc_net_get_error_string(status)));
-
-    if (sconn->callback)
-      (*sconn->callback)(server, NULL, sconn->callback_context);
-    silc_server_connection_free(sconn);
+    if (!sconn->no_reconnect) {
+      silc_schedule_task_add_timeout(sconn->server->schedule,
+                                    silc_server_connect_to_router_retry,
+                                    sconn, 1, 0);
+      silc_dlist_del(server->conns, sconn);
+    } else {
+      if (sconn->callback)
+       (*sconn->callback)(server, NULL, sconn->callback_context);
+      silc_server_connection_free(sconn);
+    }
     break;
 
   default:
@@ -1880,6 +1974,8 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
       SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
                     (sconn->backup ? "backup router" : "router"),
                     sconn->remote_host, sconn->remote_port));
+      if (sconn->callback)
+       (*sconn->callback)(server, NULL, sconn->callback_context);
       silc_server_connection_free(sconn);
       return;
     }
@@ -1896,6 +1992,8 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   if (!sconn->op) {
     SILC_LOG_ERROR(("Could not connect to router %s:%d",
                    sconn->remote_host, sconn->remote_port));
+    if (sconn->callback)
+      (*sconn->callback)(server, NULL, sconn->callback_context);
     silc_server_connection_free(sconn);
     return;
   }
@@ -1914,6 +2012,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
   SilcServer server = context;
   SilcServerConnection sconn;
   SilcServerConfigRouter *ptr;
+  SilcServerConfigConnParams *param;
 
   /* Don't connect if we are shutting down. */
   if (server->server_shutdown)
@@ -1989,6 +2088,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       }
     }
 
+    param = (ptr->param ? ptr->param : &server->config->param);
+
     /* Allocate connection object for hold connection specific stuff. */
     sconn = silc_calloc(1, sizeof(*sconn));
     if (!sconn)
@@ -2001,6 +2102,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
       sconn->backup_replace_port = ptr->backup_replace_port;
     }
+    sconn->no_reconnect = param->reconnect_keep_trying == FALSE;
 
     SILC_LOG_DEBUG(("Created connection %p", sconn));
 
@@ -2501,6 +2603,7 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
   sconn->remote_port = port;
   silc_dlist_add(server->conns, sconn);
   idata->sconn = sconn;
+  idata->sconn->callback = NULL;
   idata->last_receive = time(NULL);
 
   /* Add the common data structure to the ID entry. */
@@ -3036,6 +3139,7 @@ void silc_server_free_client_data(SilcServer server,
     client->router = NULL;
     client->connection = NULL;
     client->data.created = silc_time();
+    silc_dlist_del(server->expired_clients, client);
     silc_dlist_add(server->expired_clients, client);
   } else {
     /* Delete directly since we're shutting down server */
@@ -3155,7 +3259,7 @@ void silc_server_free_sock_user_data(SilcServer server,
 
            /* We'll need to constantly try to reconnect to the primary
               router so that we'll see when it comes back online. */
-           silc_server_create_connection(server, FALSE, FALSE, ip, port,
+           silc_server_create_connection(server, TRUE, FALSE, ip, port,
                                         silc_server_backup_connected,
                                         NULL);
          }