Added silc_server_send_opers[_notify] to send packets to operators.
[silc.git] / apps / silcd / server_backup.c
index d040d454b65d0efd5828689502a334ffe7a582da..4c262c7bdab72f0e8a0fcefd9db8b53745a3030f 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 2002 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done);
 typedef struct {
   SilcServerEntry server;
   SilcIDIP ip;
-  uint16 port;
+  SilcUInt16 port;
   bool local;
 } SilcServerBackupEntry;
 
@@ -35,20 +35,20 @@ typedef struct {
    by backup router. */
 typedef struct {
   SilcIDIP ip;
-  uint16 port;
+  SilcUInt16 port;
   SilcServerEntry server;      /* Backup router that replaced the primary */
 } SilcServerBackupReplaced;
 
 /* Backup context */
 struct SilcServerBackupStruct {
   SilcServerBackupEntry *servers;
-  uint32 servers_count;
+  SilcUInt32 servers_count;
   SilcServerBackupReplaced **replaced;
-  uint32 replaced_count;
+  SilcUInt32 replaced_count;
 };
 
 typedef struct {
-  uint8 session;
+  SilcUInt8 session;
   bool connected;
   SilcServerEntry server_entry;
 } SilcServerBackupProtocolSession;
@@ -58,10 +58,10 @@ typedef struct {
   SilcServer server;
   SilcSocketConnection sock;
   bool responder;
-  uint8 type;
-  uint8 session;
+  SilcUInt8 type;
+  SilcUInt8 session;
   SilcServerBackupProtocolSession *sessions;
-  uint32 sessions_count;
+  SilcUInt32 sessions_count;
   long start;
 } *SilcServerBackupProtocolContext;
 
@@ -90,8 +90,8 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
       server->backup->servers[i].local = local;
       memset(server->backup->servers[i].ip.data, 0,
             sizeof(server->backup->servers[i].ip.data));
-      silc_net_addr2bin_ne(ip, server->backup->servers[i].ip.data,
-                          sizeof(server->backup->servers[i].ip.data));
+      silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+                       sizeof(server->backup->servers[i].ip.data));
       //server->backup->servers[i].port = port;
       return;
     }
@@ -105,8 +105,8 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
   server->backup->servers[i].local = local;
   memset(server->backup->servers[i].ip.data, 0,
         sizeof(server->backup->servers[i].ip.data));
-  silc_net_addr2bin_ne(ip, server->backup->servers[i].ip.data,
-                      sizeof(server->backup->servers[i].ip.data));
+  silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+                   sizeof(server->backup->servers[i].ip.data));
   //server->backup->servers[i].port = server_id->port;
   server->backup->servers_count++;
 }
@@ -125,8 +125,6 @@ SilcServerEntry silc_server_backup_get(SilcServer server,
     return NULL;
 
   for (i = 0; i < server->backup->servers_count; i++) {
-    SILC_LOG_HEXDUMP(("IP"), server_id->ip.data, 16);
-    SILC_LOG_HEXDUMP(("IP"), server->backup->servers[i].ip.data, 16);
     if (server->backup->servers[i].server &&
        !memcmp(&server->backup->servers[i].ip, &server_id->ip.data,
                sizeof(server_id->ip.data)))
@@ -137,19 +135,22 @@ SilcServerEntry silc_server_backup_get(SilcServer server,
 }
 
 /* Deletes the backup server `server_entry'. */
+
 void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
 {
   int i;
 
-  SILC_LOG_DEBUG(("Start"));
-
   if (!server->backup)
     return ;
 
   for (i = 0; i < server->backup->servers_count; i++) {
     if (server->backup->servers[i].server == server_entry) {
+      SILC_LOG_DEBUG(("Removing %s as backup router",
+                     server_entry->server_name ? server_entry->server_name :
+                     ""));
       server->backup->servers[i].server = NULL;
-      return;
+      memset(server->backup->servers[i].ip.data, 0,
+            sizeof(server->backup->servers[i].ip.data));
     }
   }
 }
@@ -270,6 +271,7 @@ void silc_server_backup_broadcast(SilcServer server,
   SilcServerEntry backup;
   SilcSocketConnection sock;
   SilcBuffer buffer;
+  const SilcBufferStruct p;
   SilcIDListData idata;
   int i;
 
@@ -287,17 +289,22 @@ void silc_server_backup_broadcast(SilcServer server,
     if (!backup || backup->connection == sender || 
        server->backup->servers[i].local == FALSE)
       continue;
+    if (server->backup->servers[i].server == server->id_entry)
+      continue;
 
     idata = (SilcIDListData)backup;
     sock = backup->connection;
 
-    silc_packet_send_prepare(sock, 0, 0, buffer->len); 
-    silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, 
-                       sock->outbuf, sock->outbuf->len);
+    if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
+                                 (const SilcBuffer)&p)) {
+      SILC_LOG_ERROR(("Cannot send packet"));
+      return;
+    }
+    silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, 
+                       (SilcBuffer)&p, p.len);
 
-    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
-                    sock->outbuf->data, sock->outbuf->len);
+    SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
 
     /* Now actually send the packet */
     silc_server_packet_send_real(server, sock, FALSE);
@@ -319,7 +326,7 @@ void silc_server_backup_send(SilcServer server,
                             SilcPacketType type,
                             SilcPacketFlags flags,
                             unsigned char *data,
-                            uint32 data_len,
+                            SilcUInt32 data_len,
                             bool force_send,
                             bool local)
 {
@@ -330,8 +337,6 @@ void silc_server_backup_send(SilcServer server,
   if (!server->backup || server->server_type != SILC_ROUTER)
     return;
 
-  SILC_LOG_DEBUG(("Start"));
-
   for (i = 0; i < server->backup->servers_count; i++) {
     backup = server->backup->servers[i].server;
     if (!backup)
@@ -342,8 +347,14 @@ void silc_server_backup_send(SilcServer server,
 
     if (local && server->backup->servers[i].local == FALSE)
       continue;
+    if (server->backup->servers[i].server == server->id_entry)
+      continue;
 
     sock = backup->connection;
+
+    SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
+                   silc_get_packet_name(type), sock->hostname, sock->ip));
+
     silc_server_packet_send(server, backup->connection, type, flags, 
                            data, data_len, force_send);
   }
@@ -361,7 +372,7 @@ void silc_server_backup_send_dest(SilcServer server,
                                  void *dst_id,
                                  SilcIdType dst_id_type,
                                  unsigned char *data,
-                                 uint32 data_len,
+                                 SilcUInt32 data_len,
                                  bool force_send,
                                  bool local)
 {
@@ -372,8 +383,6 @@ void silc_server_backup_send_dest(SilcServer server,
   if (!server->backup || server->server_type != SILC_ROUTER)
     return;
 
-  SILC_LOG_DEBUG(("Start"));
-
   for (i = 0; i < server->backup->servers_count; i++) {
     backup = server->backup->servers[i].server;
     if (!backup)
@@ -384,8 +393,14 @@ void silc_server_backup_send_dest(SilcServer server,
 
     if (local && server->backup->servers[i].local == FALSE)
       continue;
+    if (server->backup->servers[i].server == server->id_entry)
+      continue;
 
     sock = backup->connection;
+
+    SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
+                   silc_get_packet_name(type), sock->hostname, sock->ip));
+
     silc_server_packet_send_dest(server, backup->connection, type, flags, 
                                 dst_id, dst_id_type, data, data_len, 
                                 force_send);
@@ -400,7 +415,7 @@ void silc_server_backup_resume_router(SilcServer server,
                                      SilcSocketConnection sock, 
                                      SilcPacketContext *packet)
 {
-  uint8 type, session;
+  SilcUInt8 type, session;
   SilcServerBackupProtocolContext ctx;
   int i, ret;
 
@@ -474,7 +489,7 @@ void silc_server_backup_resume_router(SilcServer server,
      immediately after we've connected to our primary router. */
 
   if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
-      server->router == sock->user_data &&
+      sock && SILC_PRIMARY_ROUTE(server) == sock &&
       type == SILC_SERVER_BACKUP_REPLACED) {
     /* We have been replaced by an backup router in our cell. We must
        mark our primary router connection disabled since we are not allowed
@@ -519,13 +534,15 @@ SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
   SilcServerConnection sconn = (SilcServerConnection)context;
   SilcServer server = sconn->server;
   int sock;
+  const char *server_ip;
 
   SILC_LOG_DEBUG(("Connecting to router %s:%d", sconn->remote_host,
                  sconn->remote_port));
 
   /* Connect to remote host */
-  sock = silc_net_create_connection(server->config->listen_port->local_ip,
-                                   sconn->remote_port,
+  server_ip = server->config->server_info->primary == NULL ? NULL :
+               server->config->server_info->primary->server_ip;
+  sock = silc_net_create_connection(server_ip, sconn->remote_port,
                                    sconn->remote_host);
   if (sock < 0) {
     silc_schedule_task_add(server->schedule, 0,
@@ -544,7 +561,7 @@ SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
    connection is created. */
 
 void silc_server_backup_reconnect(SilcServer server,
-                                 const char *ip, uint16 port,
+                                 const char *ip, SilcUInt16 port,
                                  SilcServerConnectRouterCallback callback,
                                  void *context)
 {
@@ -650,11 +667,39 @@ static void silc_server_backup_connect_primary(SilcServer server,
   backup_router->protocol = NULL;
 }
 
+SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcServerBackupProtocolContext ctx = protocol->context;
+  SilcServer server = ctx->server;
+  SilcBuffer packet;
+  int i;
+
+  for (i = 0; i < ctx->sessions_count; i++)
+    if (ctx->sessions[i].server_entry == ctx->sock->user_data)
+      ctx->session = ctx->sessions[i].session;
+  
+  /* We've received all the CONNECTED packets and now we'll send the
+     ENDING packet to the new primary router. */
+  packet = silc_buffer_alloc(2);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
+                    SILC_STR_UI_CHAR(ctx->session),
+                    SILC_STR_END);
+  silc_server_packet_send(server, ctx->sock, 
+                         SILC_PACKET_RESUME_ROUTER, 0, 
+                         packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+  
+  protocol->state = SILC_PROTOCOL_STATE_END;
+}
+
 /* Resume protocol with RESUME_ROUTER packet: 
 
    SILC_PACKET_RESUME_ROUTER:
 
-   <uint8 type> <uint8 Session ID>
+   <SilcUInt8 type> <SilcUInt8 Session ID>
 
    <type>          = the protocol opcode
    <Session ID>    = Identifier for this packet and any subsequent reply
@@ -839,7 +884,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       protocol->state++;
     } else {
       /* Responder of the protocol. */
-      SilcServerConfigSectionServerConnection *primary;
+      SilcServerConfigRouter *primary;
 
       /* We should have received START or START_GLOBAL packet */
       if (ctx->type != SILC_SERVER_BACKUP_START &&
@@ -854,7 +899,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       /* Connect to the primary router that was down that is now supposed
         to be back online. We send the CONNECTED packet after we've
         established the connection to the primary router. */
-      primary = silc_server_config_get_primary_router(server->config);
+      primary = silc_server_config_get_primary_router(server);
       if (primary && server->backup_primary) {
        silc_server_backup_reconnect(server,
                                     primary->host, primary->port,
@@ -922,24 +967,12 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       SILC_LOG_DEBUG(("********************************"));
       SILC_LOG_DEBUG(("Sending ENDING packet to primary"));
 
-      for (i = 0; i < ctx->sessions_count; i++)
-       if (ctx->sessions[i].server_entry == ctx->sock->user_data)
-         ctx->session = ctx->sessions[i].session;
-
-      /* We've received all the CONNECTED packets and now we'll send the
-        ENDING packet to the new primary router. */
-      packet = silc_buffer_alloc(2);
-      silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-      silc_buffer_format(packet,
-                        SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
-                        SILC_STR_UI_CHAR(ctx->session),
-                        SILC_STR_END);
-      silc_server_packet_send(server, ctx->sock, 
-                             SILC_PACKET_RESUME_ROUTER, 0, 
-                             packet->data, packet->len, FALSE);
-      silc_buffer_free(packet);
-
-      protocol->state = SILC_PROTOCOL_STATE_END;
+      /* Send with a timeout */
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_backup_send_resumed,
+                            protocol, 1, 0, SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+      return;
     } else {
       /* Responder */
 
@@ -959,7 +992,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
         to next state. */
       if (server->router &&
          !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
-         silc_server_config_is_primary_route(server->config)) {
+         silc_server_config_is_primary_route(server)) {
        /* We'll wait for RESUMED packet */
        protocol->state = SILC_PROTOCOL_STATE_END;
        break;
@@ -967,8 +1000,13 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
       /* Switch announced informations to our primary router of using the
         backup router. */
+      silc_server_update_servers_by_server(server, ctx->sock->user_data, 
+                                          server->router, TRUE);
       silc_server_update_clients_by_server(server, ctx->sock->user_data,
                                           server->router, TRUE, FALSE);
+      if (server->server_type == SILC_SERVER)
+       silc_server_update_channels_by_server(server, ctx->sock->user_data, 
+                                             server->router);
 
       packet = silc_buffer_alloc(2);
       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
@@ -1062,7 +1100,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
   case SILC_PROTOCOL_STATE_END:
     {
-      SilcIDListData idata;
       SilcServerEntry router, backup_router;
 
       /* We should have been received RESUMED packet from our primary
@@ -1076,36 +1113,42 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
       SILC_LOG_DEBUG(("********************************"));
       SILC_LOG_DEBUG(("Received RESUMED packet"));
 
-      /* We have now new primary router. All traffic goes there from now on. */
       if (server->backup_router)
        server->server_type = SILC_BACKUP_ROUTER;
 
+      /* We have now new primary router. All traffic goes there from now on. */
       router = (SilcServerEntry)ctx->sock->user_data;
       if (silc_server_backup_replaced_get(server, router->id, 
                                          &backup_router)) {
 
        if (backup_router == server->router) {
+         /* We have new primary router now */
          server->id_entry->router = router;
          server->router = router;
+         server->router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
          SILC_LOG_INFO(("Switching back to primary router %s",
                         server->router->server_name));
-         SILC_LOG_DEBUG(("Switching back to primary router %s",
-                         server->router->server_name));
+
+         /* We cannot talk to backup router connection anymore, it's
+            enabled again if primary goes down. */
+         backup_router->data.status |= SILC_IDLIST_STATUS_DISABLED;
        } else {
-         SILC_LOG_INFO(("Resuming the use of router %s",
+         /* We are connected to new primary and now continue using it */
+         router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+         SILC_LOG_INFO(("Resuming the use of primary router %s",
                         router->server_name));
-         SILC_LOG_DEBUG(("Resuming the use of router %s",
-                         router->server_name));
        }
 
-       idata = (SilcIDListData)server->router;
-       idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
-
        /* Update the client entries of the backup router to the new 
           router */
-       silc_server_update_clients_by_server(server, backup_router,
-                                            router, TRUE, FALSE);
-       silc_server_backup_replaced_del(server, backup_router);
+       silc_server_update_servers_by_server(server, backup_router, router,
+                                            FALSE);
+       silc_server_update_clients_by_server(server, NULL, router, 
+                                            FALSE, FALSE);
+       if (server->server_type == SILC_SERVER)
+         silc_server_update_channels_by_server(server, backup_router, router);
+       silc_server_backup_replaced_del(server, backup_router);
        silc_server_backup_add(server, backup_router, 
                               ctx->sock->ip, ctx->sock->port,
                               backup_router->server_type != SILC_ROUTER ?
@@ -1120,6 +1163,13 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        silc_server_announce_channels(server, 0, router->connection);
       }
 
+      /* Send notify about primary router going down to local operators */
+      SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+                            SILC_NOTIFY_TYPE_NONE,
+                            ("%s resumed the use of primary router %s",
+                             server->server_name,
+                             server->router->server_name));
+
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
@@ -1159,7 +1209,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
   SilcIDCacheList list;
   SilcIDCacheEntry id_cache;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Backup resuming protocol is ended"));
 
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
@@ -1176,6 +1226,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
        if (sock->protocol == protocol) {
          sock->protocol = NULL;
 
+         SILC_LOG_DEBUG(("***************1 %s:%d",
+                         sock->ip, sock->port));
+
          if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
            server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
        }
@@ -1196,6 +1249,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
        if (sock->protocol == protocol) {
          sock->protocol = NULL;
 
+         SILC_LOG_DEBUG(("***************2"));
+
          if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
            server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
        }