From 57ac4a9bafe15441e9349408863a9e9edb29efff Mon Sep 17 00:00:00 2001 From: Matthias van der Vlies Date: Fri, 28 Oct 2022 19:59:27 +0200 Subject: [PATCH] Implement SCTP multi-homing for JDiameter, both client and server Signed-off-by: Matthias van der Vlies --- .../transport/sctp/SCTPClientConnection.java | 24 +++++++++++++++++++ .../transport/sctp/SCTPTransportClient.java | 17 ++++++++++++- .../server/impl/io/sctp/NetworkGuard.java | 15 +++++++++--- .../impl/io/sctp/SCTPServerConnection.java | 3 ++- .../impl/io/sctp/SCTPTransportServer.java | 12 +++++++++- 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPClientConnection.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPClientConnection.java index 28496d1c2..36bd397cf 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPClientConnection.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPClientConnection.java @@ -77,6 +77,7 @@ public SCTPClientConnection(Configuration config, IConcurrentFactory concurrentF localAddress, localPort }); client.setDestAddress(new InetSocketAddress(remoteAddress, remotePort)); client.setOrigAddress(new InetSocketAddress(localAddress, localPort)); + client.setExtraHostAddresses(getExtraLocalIPAddresses(config)); } public SCTPClientConnection(Configuration config, IConcurrentFactory concurrentFactory, InetAddress remoteAddress, @@ -87,9 +88,32 @@ public SCTPClientConnection(Configuration config, IConcurrentFactory concurrentF localAddress, localPort }); client.setDestAddress(new InetSocketAddress(remoteAddress, remotePort)); client.setOrigAddress(new InetSocketAddress(localAddress, localPort)); + client.setExtraHostAddresses(getExtraLocalIPAddresses(config)); listeners.add(listener); } + private static String[] getExtraLocalIPAddresses(Configuration config) { + String[] extraLocalIPAddresses = null; + + if (!config.isAttributeExist(org.jdiameter.server.impl.helpers.Parameters.OwnIPAddresses.ordinal())) { + throw new IllegalArgumentException("No IPAddresses attribute present in local peer!"); + } else { + final Configuration[] ownIPAddresses = config.getChildren(org.jdiameter.server.impl.helpers.Parameters.OwnIPAddresses.ordinal()); + if (ownIPAddresses.length > 4) { + throw new IllegalArgumentException("Maximum of 4 IPAddress attributes allowed"); + } + + extraLocalIPAddresses = new String[ownIPAddresses.length - 1]; + + for(int i = 1; i < ownIPAddresses.length; i++) { + final String localIPAddress = ownIPAddresses[i].getStringValue(org.jdiameter.server.impl.helpers.Parameters.OwnIPAddress.ordinal(), ""); + extraLocalIPAddresses[i - 1] = localIPAddress; + logger.debug("Adding extra local IP address [{}]", localIPAddress); + } + } + return extraLocalIPAddresses; + } + @Override public long getCreatedTime() { return createdTime; diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPTransportClient.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPTransportClient.java index 4ab2bcfab..4ab5624c7 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPTransportClient.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/sctp/SCTPTransportClient.java @@ -55,6 +55,8 @@ public class SCTPTransportClient { private String clientAssociationName; protected InetSocketAddress destAddress; protected InetSocketAddress origAddress; + + protected String[] extraHostAddresses; private int payloadProtocolId = 0; private int streamNumber = 0; @@ -109,7 +111,7 @@ public void initialize() throws IOException, NotInitializedException { clientAssociationName, origAddress, destAddress }); this.clientAssociation = this.management.addAssociation(origAddress.getAddress().getHostAddress(), origAddress.getPort(), destAddress.getAddress().getHostAddress(), destAddress.getPort(), clientAssociationName, - IpChannelType.SCTP, null); + IpChannelType.SCTP, extraHostAddresses); } else { logger.debug("CLIENT ASSOCIATION '{}'. Origin Address [{}:{}] <=> Dest Address [{}:{}] already present. Re-using it.", @@ -289,6 +291,19 @@ public InetSocketAddress getOrigAddress() { return this.origAddress; } + public void setExtraHostAddresses(String[] extraHostAddresses) { + this.extraHostAddresses = extraHostAddresses; + if (logger.isDebugEnabled() && extraHostAddresses != null) { + for(final String address : extraHostAddresses) { + logger.debug("Extra host address is set to [{}]", address); + } + } + } + + public String[] getExtraHostAddresses() { + return this.extraHostAddresses; + } + public void sendMessage(ByteBuffer bytes) throws IOException { if (logger.isDebugEnabled()) { logger.debug("About to send a byte buffer of size [{}] over the SCTP", bytes.array().length); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/NetworkGuard.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/NetworkGuard.java index 07bd3bdab..0723d9777 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/NetworkGuard.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/NetworkGuard.java @@ -73,10 +73,19 @@ public NetworkGuard(InetAddress[] inetAddresses, int port, IConcurrentFactory co this.serverConnections = new ArrayList(); try { - for (InetAddress ia : inetAddresses) { - final SCTPServerConnection sctpServerConnection = new SCTPServerConnection(null, ia, port, parser, null, this); - this.serverConnections.add(sctpServerConnection); + if (localAddresses.length < 1) { + throw new Exception("Need at least one IP address configured"); + } else if (localAddresses.length > 4) { + throw new IllegalArgumentException("Maximum of 4 IPAddress attributes allowed"); } + + final InetAddress firstAddress = localAddresses[0]; + final String[] extraHostAddresses = localAddresses.length > 1 ? new String[localAddresses.length - 1] : null; + for(int i = 1; i < localAddresses.length; i++) { + extraHostAddresses[i - 1] = localAddresses[i].getHostAddress(); + } + final SCTPServerConnection sctpServerConnection = new SCTPServerConnection(null, firstAddress, port, parser, null, this, extraHostAddresses); + this.serverConnections.add(sctpServerConnection); } catch (Exception exc) { try { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPServerConnection.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPServerConnection.java index 16680462a..d3f9947c7 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPServerConnection.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPServerConnection.java @@ -72,11 +72,12 @@ protected SCTPServerConnection(IMessageParser parser, NetworkGuard guard) { // this creates the listening server - no dest address is passed it is automatically 0.0.0.0:0 public SCTPServerConnection(Configuration config, InetAddress localAddress, int localPort, IMessageParser parser, String ref, - NetworkGuard guard) throws Exception { + NetworkGuard guard, String[] extraHostAddresses) throws Exception { this(parser, guard); logger.debug("SCTP Server constructor for listening server @ {}:{}", localAddress, localPort); server.setOrigAddress(new InetSocketAddress(localAddress, localPort)); + server.setExtraHostAddresses(extraHostAddresses); server.startServer(); } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPTransportServer.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPTransportServer.java index bd1fe9c9a..9475128f8 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPTransportServer.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/io/sctp/SCTPTransportServer.java @@ -53,6 +53,7 @@ public class SCTPTransportServer { private String serverName; protected InetSocketAddress destAddress; protected InetSocketAddress origAddress; + protected String[] extraHostAddresses; private Server server = null; private static final Logger logger = LoggerFactory.getLogger(SCTPTransportServer.class); private int payloadProtocolId = 0; @@ -161,7 +162,7 @@ public void startServer() throws NotInitializedException { // We don't have any, let's create it if (server == null) { server = this.management.addServer(serverName, origAddress.getAddress().getHostAddress(), origAddress.getPort(), - IpChannelType.SCTP, true, 10, null); + IpChannelType.SCTP, true, 10, extraHostAddresses); } for (String assocName : server.getAssociations()) { @@ -381,6 +382,15 @@ public void setOrigAddress(InetSocketAddress address) { } } + public void setExtraHostAddresses(String[] extraHostAddresses) { + this.extraHostAddresses = extraHostAddresses; + if (logger.isDebugEnabled() && extraHostAddresses != null) { + for(final String address : extraHostAddresses) { + logger.debug("Extra host address is set to [{}]", address); + } + } + } + public InetSocketAddress getOrigAddress() { return this.origAddress; }