From 0a92115d56e91837531ba7da2312af29952181b4 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Wed, 23 Sep 2026 12:37:01 +0000
Subject: [PATCH] [#1017] Recognise a replication server by the address it names, not by the one its session came from (#1020)
---
opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java | 55 +++++++++++++++++++++++++++++--------------------------
1 files changed, 29 insertions(+), 26 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
index 961cd88..f83b4ed 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
@@ -607,11 +607,9 @@
* cannot guarantee this since the configuration may not contain this
* RS.
*/
- final Set<HostPort> connectedRSAddresses =
- getConnectedRSAddresses(domain);
for (HostPort rsAddress : configuredRSAddresses)
{
- if (connectedRSAddresses.contains(rsAddress))
+ if (domain.isConnectedToServerAt(rsAddress))
{
// Skip: already connected. The connection may be the one that peer made to
// this server, which connect() never sees, so this is where a failure
@@ -671,16 +669,6 @@
}
}
- private Set<HostPort> getConnectedRSAddresses(ReplicationServerDomain domain)
- {
- Set<HostPort> results = new HashSet<>();
- for (ReplicationServerHandler rsHandler : domain.getConnectedRSs().values())
- {
- results.add(HostPort.valueOf(rsHandler.getServerAddressURL()));
- }
- return results;
- }
-
/**
* Establish a connection to the server with the address and port.
* <p>
@@ -767,13 +755,15 @@
* ReplicationServerHandler.connect() registers only above V1, the FIXME there being
* older than this, so such a peer is connected and never registered.
*
- * the address, and the session left open with it, miss a peer which dials out from an
- * address other than the one it is configured under -- multi homing, NAT. Its inbound
- * handler is registered under the source address of its own connection,
- * ServerHandler.toServerAddressURL() reading the host from the session, so the already
- * connected branch of runConnect() compares the configured address against one it never
- * matches, and the handshake this server offers that same peer aborts on a duplicate
- * server id: abortStart() closes the session, and an open session is never seen here
+ * the address, and the session left open with it, miss a peer which names an address
+ * this configuration does not use -- the host name of its machine, which setServerURL()
+ * falls back to when none of the addresses it is configured with is local to it -- and
+ * dials out from another one this configuration does not use either: multi homing,
+ * NAT. Its inbound handler is known by the address it named and by the source address
+ * of its own connection, and the already connected branch of runConnect() finds the
+ * configured address under neither, so this server offers that same peer a handshake
+ * which either end resolves as a cross connect, on the address both handlers of the
+ * peer name: abortStart() closes the session, and an open session is never seen here
* again.
*
* An outage left open is not a line too few but a peer gone silent: recordFailure()
@@ -795,11 +785,15 @@
* with the same silent abortStart(null), one line up in startFromRemoteRS().
*
* The cross connect this server resolves is the one abort of the three where a session
- * for the domain does exist: it is the connection the peer made, which the already
- * connected branch of runConnect() reports on its next pass. Reaching this line with
- * one open needs that registration to land between the snapshot that branch reads and
- * the dial below it, so what it costs is one warning, and the pass after it says what
- * is true.
+ * for the domain does exist: it is the connection the peer made. For a peer which names
+ * an address this configuration uses, that is the session the already connected branch
+ * of runConnect() reports on its next pass; reaching this line with it open needs the
+ * registration to land between the check that branch makes and the dial below it, so
+ * what it costs is one warning, and the pass after it says what is true. For the peer
+ * of the second reading above no pass matches it, so what was last said of it stays
+ * said -- nothing where no outage was reported, the warning where one was -- and the
+ * blacklist runConnect() keeps for an answer without a session is what bounds the
+ * dialling behind it.
*/
reportConnectionRestored(remoteServerAddress, baseDN, handshakeCompleted);
return handshakeCompleted;
@@ -2044,10 +2038,19 @@
{
final Collection<HostPort> serversToDisconnect = new ArrayList<>();
+ /*
+ * The entry of this server is never one to disconnect, and is skipped here as
+ * runConnect() skips it before it dials: this server holds no session with itself, and
+ * a peer which names a loopback address of its own machine on this port does answer to
+ * that entry, because HostPort folds every address local to this machine to localhost.
+ * Removing the entry of this server -- a list without it is supported, see
+ * runConnect() -- would otherwise stop the session of such a peer once.
+ */
+ final HostPort localAddress = HostPort.localAddress(getReplicationPort());
final Set<HostPort> newRSAddresses = getConfiguredRSAddresses();
for (HostPort oldRSAddress : oldRSAddresses)
{
- if (!newRSAddresses.contains(oldRSAddress))
+ if (!newRSAddresses.contains(oldRSAddress) && !oldRSAddress.equals(localAddress))
{
serversToDisconnect.add(oldRSAddress);
}
--
Gitblit v1.10.0