Added silc_server_send_opers[_notify] to send packets to operators.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 24 Jun 2002 18:55:39 +0000 (18:55 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 24 Jun 2002 18:55:39 +0000 (18:55 +0000)
Fixed UMODE_CHANGE notify handling.
Fixed backup router issues after resuming protocol is completed.
Connections that were unconfigured in rehash are now closed
automatically.

CHANGES
TODO
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_backup.c
apps/silcd/server_util.c
apps/silcd/server_util.h

diff --git a/CHANGES b/CHANGES
index 837f2525820846c0ee77abcd3088f0c7b1808271..b7f4ad81f237c33b7a9f244eaa148dc29da25be8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,29 @@
+Mon Jun 24 17:47:52 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+       * Added functions silc_server_send_opers and
+         silc_server_send_opers_notify to send packets stricly
+         to operators.  Added macro SILC_SERVER_SEND_OPERS macro
+         to send variable argument notify to operators.
+         Affected files silcd/packet_send.[ch] and silcd/server.h.
+
+       * Removed UMODE rights checking with UMODE_CHANGE notify.
+         Affected file silcd/packet_receive.c.
+
+       * Server/router operator now receives notify when network
+         switches to backup router and when it resumes the use of
+         primary router.  Affected file silcd/server.c and
+         silcd/server_backup.c.
+
+       * Fixed the updating of client information after backup
+         resuming protocol is over; update all except local clients
+         to the new primary router.  The affected file is
+         silcd/server_util.c.
+
+       * Added support for closing active connections in rehash
+         that were unconfigured by the user.  Supports currently
+         closing server and router connections.  Affected file
+         silcd/server.c.
+
 Sun Jun 23 17:32:31 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
 
        * Don't do SILC_STRING_LANGUAGE encoding if the outbuffer
 Sun Jun 23 17:32:31 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
 
        * Don't do SILC_STRING_LANGUAGE encoding if the outbuffer
diff --git a/TODO b/TODO
index 71863c8ace06b839eaf42d2ebdb2023ffdbe3493..0c4fa20d5d9ddbeedc082c72c29a655c106685d9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -35,10 +35,6 @@ TODO/bugs In SILC Server
          cell use it.  When primary goes down, also those that are
          not using it (are not connected locally) are signoffed.
 
          cell use it.  When primary goes down, also those that are
          not using it (are not connected locally) are signoffed.
 
-       o Configure use of backup router on normal server using HUP.
-
-       o Configure use of backup router on router using HUP.
-
        o Rewrite SILC_LOG_DEBUG's in silcd/server_backup.c.
 
        o Testing
        o Rewrite SILC_LOG_DEBUG's in silcd/server_backup.c.
 
        o Testing
index a9f3f267f9300271910401ba816adc04f05c9224..4abfcfb86ba5a70f822fd47e9c96b9b3fd5e65cc 100644 (file)
@@ -1551,12 +1551,6 @@ void silc_server_notify(SilcServer server,
       goto out;
     SILC_GET32_MSB(mode, tmp);
 
       goto out;
     SILC_GET32_MSB(mode, tmp);
 
-    /* Check that mode changing is allowed. */
-    if (!silc_server_check_umode_rights(server, client, mode)) {
-      SILC_LOG_DEBUG(("UMODE change is not allowed"));
-      goto out;
-    }
-
     /* Remove internal resumed flag if client is marked detached now */
     if (mode & SILC_UMODE_DETACHED)
       client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
     /* Remove internal resumed flag if client is marked detached now */
     if (mode & SILC_UMODE_DETACHED)
       client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
index 818ec0f015a3209a108a4fb571c705535f1842f2..5a60a9f9c00d7fb648876c2808f16e84143cf31a 100644 (file)
@@ -1911,3 +1911,183 @@ void silc_server_packet_queue_purge(SilcServer server,
     silc_buffer_clear(sock->outbuf);
   }
 }
     silc_buffer_clear(sock->outbuf);
   }
 }
+
+/* Send packet to clients that are known to be operators.  If server
+   is router and `route' is TRUE then the packet would go to all operators
+   in the SILC network.  If `route' is FALSE then only local operators
+   (local for server and cell wide for router).  If `local' is TRUE then
+   only locally connected operators receive the packet.  If `local' is
+   TRUE then `route' is ignored.  If server is normal server and `route'
+   is FALSE it is equivalent to `local' being TRUE. */
+
+void silc_server_send_opers(SilcServer server,
+                           SilcPacketType type,
+                           SilcPacketFlags flags,
+                           bool route, bool local,
+                           unsigned char *data, 
+                           SilcUInt32 data_len,
+                           bool force_send)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client = NULL;
+  SilcSocketConnection sock;
+  SilcServerEntry *routed = NULL;
+  SilcUInt32 routed_count = 0;
+  bool gone = FALSE;
+  int k;
+
+  SILC_LOG_DEBUG(("Sending %s packet to operators",
+                 silc_get_packet_name(type)));
+
+  /* If local was requested send only locally connected operators. */
+  if (local || (server->server_type == SILC_SERVER && !route)) {
+    if (!silc_idcache_get_all(server->local_list->clients, &list) ||
+       !silc_idcache_list_first(list, &id_cache))
+      return;
+    while (id_cache) {
+      client = (SilcClientEntry)id_cache->context;
+      if (!client->router && SILC_IS_LOCAL(client) &&
+         (client->mode & SILC_UMODE_SERVER_OPERATOR ||
+          client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+
+       /* Send the packet to locally connected operator */
+       silc_server_packet_send_dest(server, client->connection, type, flags,
+                                    client->id, SILC_ID_CLIENT,
+                                    data, data_len, force_send);
+      }
+
+      if (!silc_idcache_list_next(list, &id_cache))
+       break;
+    }
+    silc_idcache_list_free(list);
+    return;
+  }
+
+  if (!silc_idcache_get_all(server->local_list->clients, &list) ||
+      !silc_idcache_list_first(list, &id_cache))
+    return;
+  while (id_cache) {
+    client = (SilcClientEntry)id_cache->context;
+    if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+       !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+      goto next;
+
+    if (server->server_type != SILC_SERVER && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       goto next;
+
+      /* Route only once to router */
+      sock = (SilcSocketConnection)client->router->connection;
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
+         goto next;
+       gone = TRUE;
+      }
+
+      /* Send the packet */
+      silc_server_packet_send_dest(server, sock, type, flags,
+                                  client->id, SILC_ID_CLIENT,
+                                  data, data_len, force_send);
+
+      /* Mark this route routed already */
+      routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+      routed[routed_count++] = client->router;
+      goto next;
+    }
+
+    if (client->router || !client->connection)
+      goto next;
+
+    /* Send to locally connected client */
+    sock = (SilcSocketConnection)client->connection;
+    silc_server_packet_send_dest(server, sock, type, flags,
+                                client->id, SILC_ID_CLIENT,
+                                data, data_len, force_send);
+
+  next:
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+  }
+  silc_idcache_list_free(list);
+
+  if (!silc_idcache_get_all(server->global_list->clients, &list) ||
+      !silc_idcache_list_first(list, &id_cache))
+    return;
+  while (id_cache) {
+    client = (SilcClientEntry)id_cache->context;
+    if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+       !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+      goto nextg;
+
+    if (server->server_type != SILC_SERVER && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       goto nextg;
+
+      /* Route only once to router */
+      sock = (SilcSocketConnection)client->router->connection;
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
+         goto nextg;
+       gone = TRUE;
+      }
+
+      /* Send the packet */
+      silc_server_packet_send_dest(server, sock, type, flags,
+                                  client->id, SILC_ID_CLIENT,
+                                  data, data_len, force_send);
+
+      /* Mark this route routed already */
+      routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+      routed[routed_count++] = client->router;
+      goto nextg;
+    }
+
+    if (client->router || !client->connection)
+      goto nextg;
+
+    /* Send to locally connected client */
+    sock = (SilcSocketConnection)client->connection;
+    silc_server_packet_send_dest(server, sock, type, flags,
+                                client->id, SILC_ID_CLIENT,
+                                data, data_len, force_send);
+
+  nextg:
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+  }
+  silc_idcache_list_free(list);
+  silc_free(routed);
+}
+
+/* Send a notify packet to operators */
+
+void silc_server_send_opers_notify(SilcServer server,
+                                  bool route,
+                                  bool local,
+                                  SilcNotifyType type,
+                                  SilcUInt32 argc, ...)
+{
+  va_list ap;
+  SilcBuffer packet;
+
+  va_start(ap, argc);
+  packet = silc_notify_payload_encode(type, argc, ap);
+  silc_server_send_opers(server, SILC_PACKET_NOTIFY, 0,
+                        route, local, packet->data, packet->len,
+                        FALSE);
+  silc_buffer_free(packet);
+  va_end(ap);
+}
index ca0779e922741ec7144f700ad753010ccac90c6a..ec3d1f460a4696665d48d50048f53142039ef94b 100644 (file)
@@ -61,7 +61,7 @@ void silc_server_packet_route(SilcServer server,
                              SilcPacketContext *packet);
 void silc_server_packet_send_clients(SilcServer server,
                                     SilcHashTable clients,
                              SilcPacketContext *packet);
 void silc_server_packet_send_clients(SilcServer server,
                                     SilcHashTable clients,
-                                    SilcPacketType type, 
+                                    SilcPacketType type,
                                     SilcPacketFlags flags,
                                     bool route,
                                     unsigned char *data, 
                                     SilcPacketFlags flags,
                                     bool route,
                                     unsigned char *data, 
@@ -267,5 +267,17 @@ void silc_server_send_connection_auth_request(SilcServer server,
                                              SilcAuthMethod auth_meth);
 void silc_server_packet_queue_purge(SilcServer server,
                                    SilcSocketConnection sock);
                                              SilcAuthMethod auth_meth);
 void silc_server_packet_queue_purge(SilcServer server,
                                    SilcSocketConnection sock);
+void silc_server_send_opers(SilcServer server,
+                           SilcPacketType type,
+                           SilcPacketFlags flags,
+                           bool route, bool local,
+                           unsigned char *data, 
+                           SilcUInt32 data_len,
+                           bool force_send);
+void silc_server_send_opers_notify(SilcServer server,
+                                  bool route,
+                                  bool local,
+                                  SilcNotifyType type,
+                                  SilcUInt32 argc, ...);
 
 #endif
 
 #endif
index fb135c4cfc66765513e938bd0d7894ef65837298..0a8921c382f1a7698a5d3df86a1572f471128037 100644 (file)
@@ -28,6 +28,7 @@
 #include "server_internal.h"
 
 /* Static prototypes */
 #include "server_internal.h"
 
 /* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
 SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
 SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_connect_to_router);
@@ -448,6 +449,31 @@ bool silc_server_init(SilcServer server)
   return FALSE;
 }
 
   return FALSE;
 }
 
+/* Task callback to close a socket connection after rehash */
+
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
+{
+  SilcServer server = context;
+  SilcSocketConnection sock = server->sockets[fd];
+
+  if (!sock)
+    return;
+
+  SILC_LOG_INFO(("Closing connection %s:%d [%s]: connection is unconfigured",
+                sock->hostname, sock->port,
+                (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                 sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                 sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                 "Router")));
+  silc_schedule_task_del_by_context(server->schedule, sock);
+  silc_server_disconnect_remote(server, sock,
+                               SILC_STATUS_ERR_BANNED_FROM_SERVER,
+                               "This connection is removed from "
+                               "configuration");
+  if (sock->user_data)
+    silc_server_free_sock_user_data(server, sock, NULL);
+}
+
 /* This function basically reads the config file again and switches the config
    object pointed by the server object. After that, we have to fix various
    things such as the server_name and the listening ports.
 /* This function basically reads the config file again and switches the config
    object pointed by the server object. After that, we have to fix various
    things such as the server_name and the listening ports.
@@ -516,6 +542,70 @@ bool silc_server_rehash(SilcServer server)
     silc_pkcs_private_key_set(server->pkcs, server->private_key);
   }
 
     silc_pkcs_private_key_set(server->pkcs, server->private_key);
   }
 
+  /* Check for unconfigured server and router connections and close
+     connections that were unconfigured. */
+
+  if (server->config->routers) {
+    SilcServerConfigRouter *ptr;
+    SilcServerConfigRouter *newptr;
+    bool found;
+
+    for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
+       if (!strcmp(newptr->host, ptr->host) && newptr->port == ptr->port &&
+           newptr->initiator == ptr->initiator) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+                                              ptr->host, ptr->port);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
+  if (server->config->servers) {
+    SilcServerConfigServer *ptr;
+    SilcServerConfigServer *newptr;
+    bool found;
+
+    for (ptr = server->config->servers; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
+       if (!strcmp(newptr->host, ptr->host)) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
+                                              ptr->host, 0);
+       if (sock && !SILC_IS_LISTENER(sock))
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
   /* Go through all configured routers after rehash */
   silc_schedule_task_add(server->schedule, 0,
                         silc_server_connect_to_router,
   /* Go through all configured routers after rehash */
   silc_schedule_task_add(server->schedule, 0,
                         silc_server_connect_to_router,
@@ -2865,6 +2955,20 @@ void silc_server_free_sock_user_data(SilcServer server,
        if (server->server_type == SILC_SERVER)
          silc_server_update_channels_by_server(server, user_data,
                                                backup_router);
        if (server->server_type == SILC_SERVER)
          silc_server_update_channels_by_server(server, user_data,
                                                backup_router);
+
+       /* Send notify about primary router going down to local operators */
+       if (server->backup_router)
+         SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+                                SILC_NOTIFY_TYPE_NONE,
+                                ("%s switched to backup router %s "
+                                 "(we are primary router now)",
+                                 server->server_name, server->server_name));
+       else
+         SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+                                SILC_NOTIFY_TYPE_NONE,
+                                ("%s switched to backup router %s",
+                                 server->server_name,
+                                 server->router->server_name));
       }
 
       /* Free the server entry */
       }
 
       /* Free the server entry */
index d318233ec65e9fa69bd0fc6a94fdcc00723028ed..5ba6a0bacb417627446b13b14cd52b18a2a5c247 100644 (file)
@@ -98,7 +98,16 @@ do {                                                         \
   silc_server_send_notify(server, sock, FALSE,                         \
                          type, 1, __fmt__, strlen(__fmt__));   \
   silc_free(__fmt__);                                          \
   silc_server_send_notify(server, sock, FALSE,                         \
                          type, 1, __fmt__, strlen(__fmt__));   \
   silc_free(__fmt__);                                          \
-} while(0);
+} while(0)
+
+/* Send notify to operators */
+#define SILC_SERVER_SEND_OPERS(server, route, local, type, fmt)                \
+do {                                                                   \
+  char *__fmt__ = silc_format fmt;                                     \
+  silc_server_send_opers_notify(server, route, local,                  \
+                               type, 1, __fmt__, strlen(__fmt__));     \
+  silc_free(__fmt__);                                                  \
+} while(0)
 
 /* Check whether rekey protocol is active */
 #define SILC_SERVER_IS_REKEY(sock)                                     \
 
 /* Check whether rekey protocol is active */
 #define SILC_SERVER_IS_REKEY(sock)                                     \
index 299f1eee1b681e8700a27aaf2d3338f0d6b64786..4c262c7bdab72f0e8a0fcefd9db8b53745a3030f 100644 (file)
@@ -1144,8 +1144,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
           router */
        silc_server_update_servers_by_server(server, backup_router, router,
                                             FALSE);
           router */
        silc_server_update_servers_by_server(server, backup_router, router,
                                             FALSE);
-       silc_server_update_clients_by_server(server, backup_router,
-                                            router, TRUE, 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);
        if (server->server_type == SILC_SERVER)
          silc_server_update_channels_by_server(server, backup_router, router);
        silc_server_backup_replaced_del(server, backup_router);
@@ -1163,6 +1163,13 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        silc_server_announce_channels(server, 0, router->connection);
       }
 
        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);
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
index a09a9d90e120013d1010c3eda7775b31dd686854..121bb8d88034f9f361ee54ffbc8846957f0ef76f 100644 (file)
@@ -462,7 +462,8 @@ silc_server_update_clients_by_real_server(SilcServer server,
    be the new source. This function also removes the clients that are
    *really* originated from `from' if `remove_from' is TRUE. These are
    clients that the `from' owns, and not just clients that are behind
    be the new source. This function also removes the clients that are
    *really* originated from `from' if `remove_from' is TRUE. These are
    clients that the `from' owns, and not just clients that are behind
-   the `from'. */
+   the `from'. If `from' is NULL then all non-local clients are switched
+   to `to'. */
 
 void silc_server_update_clients_by_server(SilcServer server, 
                                          SilcServerEntry from,
 
 void silc_server_update_clients_by_server(SilcServer server, 
                                          SilcServerEntry from,
@@ -506,26 +507,31 @@ void silc_server_update_clients_by_server(SilcServer server,
          SILC_LOG_DEBUG(("Client->router (global) %s", 
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
          SILC_LOG_DEBUG(("Client->router (global) %s", 
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
-       if (client->router == from) {
-         /* Skip clients that are *really* owned by the `from' */
-         if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
-                                            client->id->ip.data_len)) {
-           SILC_LOG_DEBUG(("Found really owned client, skip it"));
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-           else
-             continue;
-         }
-
-         if (resolve_real_server) {
-           client->router = 
-             silc_server_update_clients_by_real_server(server, from, client,
-                                                       local, id_cache);
-           if (!client->router)
+       if (from) {
+         if (client->router == from) {
+           /* Skip clients that are *really* owned by the `from' */
+           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
+                                              client->id->ip.data_len)) {
+             SILC_LOG_DEBUG(("Found really owned client, skip it"));
+             if (!silc_idcache_list_next(list, &id_cache))
+               break;
+             else
+               continue;
+           }
+
+           if (resolve_real_server) {
+             client->router = 
+               silc_server_update_clients_by_real_server(server, from, client,
+                                                         local, id_cache);
+             if (!client->router)
+               client->router = to;
+           } else {
              client->router = to;
              client->router = to;
-         } else {
-           client->router = to;
+           }
          }
          }
+       } else {
+         /* All are changed */
+         client->router = to;
        }
 
        if (!silc_idcache_list_next(list, &id_cache))
        }
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -557,26 +563,31 @@ void silc_server_update_clients_by_server(SilcServer server,
          SILC_LOG_DEBUG(("Client->router (local) %s", 
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
          SILC_LOG_DEBUG(("Client->router (local) %s", 
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
-       if (client->router == from) {
-         /* Skip clients that are *really* owned by the `from' */
-         if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
-                                            client->id->ip.data_len)) {
-           SILC_LOG_DEBUG(("Found really owned client, skip it"));
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-           else
-             continue;
-         }
-
-         if (resolve_real_server) {
-           client->router = 
-             silc_server_update_clients_by_real_server(server, from, client,
-                                                       local, id_cache);
-           if (!client->router)
-             client->router = from; /* on local list put old from */
-         } else {
-           client->router = to;
+       if (from) {
+         if (client->router == from) {
+           /* Skip clients that are *really* owned by the `from' */
+           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
+                                              client->id->ip.data_len)) {
+             SILC_LOG_DEBUG(("Found really owned client, skip it"));
+             if (!silc_idcache_list_next(list, &id_cache))
+               break;
+             else
+               continue;
+           }
+
+           if (resolve_real_server) {
+             client->router = 
+               silc_server_update_clients_by_real_server(server, from, client,
+                                                         local, id_cache);
+             if (!client->router)
+               client->router = from; /* on local list put old from */
+           } else {
+             client->router = to;
+           }
          }
          }
+       } else {
+         /* All are changed */
+         client->router = to;
        }
 
        if (!silc_idcache_list_next(list, &id_cache))
        }
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -1527,3 +1538,25 @@ bool silc_server_force_cumode_change(SilcServer server,
 
   return TRUE;
 }
 
   return TRUE;
 }
+
+/* Find active socket connection by the IP address and port indicated by
+   `ip' and `port', and socket connection type of `type'. */
+
+SilcSocketConnection
+silc_server_find_socket_by_host(SilcServer server,
+                               SilcSocketType type,
+                               const char *ip, SilcUInt16 port)
+{
+  int i;
+
+  for (i = 0; i < server->config->param.connections_max; i++) {
+    if (!server->sockets[i])
+      continue;
+    if (!strcmp(server->sockets[i]->ip, ip) &&
+       (!port || server->sockets[i]->port == port) &&
+       server->sockets[i]->type == type)
+      return server->sockets[i];
+  }
+
+  return NULL;
+}
index 6f67e25c5669fc32fba37e7cd11e5f5b6e88c498..ec434bc2ef99bb9b64da9e9cbb27809ac4818772 100644 (file)
@@ -37,7 +37,8 @@ bool silc_server_remove_clients_by_server(SilcServer server,
    be the new source. This function also removes the clients that are
    *really* originated from `from' if `remove_from' is TRUE. These are
    clients that the `from' owns, and not just clients that are behind
    be the new source. This function also removes the clients that are
    *really* originated from `from' if `remove_from' is TRUE. These are
    clients that the `from' owns, and not just clients that are behind
-   the `from'. */
+   the `from'. If `from' is NULL then all non-local clients are switched
+   to `to'. */
 void silc_server_update_clients_by_server(SilcServer server, 
                                          SilcServerEntry from,
                                          SilcServerEntry to,
 void silc_server_update_clients_by_server(SilcServer server, 
                                          SilcServerEntry from,
                                          SilcServerEntry to,
@@ -97,7 +98,7 @@ char *silc_server_name_modify_bad(const char *name, SilcUInt32 name_len);
 SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
                                         SilcSocketType type);
 
 SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
                                         SilcSocketType type);
 
-/* Find number of sockets by IP address indicated by remote host, indicatd
+/* Find number of sockets by IP address indicated by remote host, indicated
    by `ip' or `hostname', `port', and `type'.  Returns 0 if socket connections
    does not exist. If `ip' is provided then `hostname' is ignored. */
 SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server, 
    by `ip' or `hostname', `port', and `type'.  Returns 0 if socket connections
    does not exist. If `ip' is provided then `hostname' is ignored. */
 SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server, 
@@ -180,4 +181,11 @@ bool silc_server_force_cumode_change(SilcServer server,
                                     SilcChannelClientEntry chl,
                                     SilcUInt32 forced_mode);
 
                                     SilcChannelClientEntry chl,
                                     SilcUInt32 forced_mode);
 
+/* Find active socket connection by the IP address and port indicated by
+   `ip' and `port', and socket connection type of `type'. */
+SilcSocketConnection
+silc_server_find_socket_by_host(SilcServer server,
+                               SilcSocketType type,
+                               const char *ip, SilcUInt16 port);
+
 #endif /* SERVER_UTIL_H */
 #endif /* SERVER_UTIL_H */