Updated aeron (and other libraries) to fix IPv6 bug (removed class override)
This commit is contained in:
parent
64a36cb4f8
commit
ed60b68e77
@ -35,14 +35,14 @@ plugins {
|
||||
id("com.dorkbox.GradlePublish") version "1.8"
|
||||
id("com.dorkbox.GradleModuleInfo") version "1.1"
|
||||
|
||||
kotlin("jvm") version "1.4.0"
|
||||
kotlin("jvm") version "1.4.10"
|
||||
}
|
||||
|
||||
object Extras {
|
||||
// set for the project
|
||||
const val description = "Encrypted, high-performance, and event-driven/reactive network stack for Java 11+"
|
||||
const val group = "com.dorkbox"
|
||||
const val version = "5.0-beta6"
|
||||
const val version = "5.0-beta7"
|
||||
|
||||
// set as project.ext
|
||||
const val name = "Network"
|
||||
@ -201,7 +201,7 @@ dependencies {
|
||||
|
||||
|
||||
// https://github.com/real-logic/aeron
|
||||
val aeronVer = "1.29.0"
|
||||
val aeronVer = "1.30.0"
|
||||
// REMOVE UdpChannel when ISSUE https://github.com/real-logic/aeron/issues/1057 is resolved! (hopefully in 1.30.0)
|
||||
implementation("io.aeron:aeron-client:$aeronVer")
|
||||
implementation("io.aeron:aeron-driver:$aeronVer")
|
||||
@ -228,7 +228,14 @@ dependencies {
|
||||
implementation("com.dorkbox:Annotations:3.1")
|
||||
implementation("com.dorkbox:MinLog-SLF4J:2.0")
|
||||
implementation("com.dorkbox:Utilities:1.8.2")
|
||||
implementation("com.dorkbox:NetworkUtils:1.5")
|
||||
implementation("com.dorkbox:NetworkUtils:2.0")
|
||||
|
||||
// really fast storage
|
||||
// https://github.com/lmdbjava/lmdbjava
|
||||
implementation("org.lmdbjava:lmdbjava:0.8.1")
|
||||
// https://github.com/OpenHFT/Chronicle-Map
|
||||
implementation("net.openhft:chronicle-map:3.20.3")
|
||||
|
||||
|
||||
// Caffeine High-throughput Timeout Cache
|
||||
// https://github.com/ben-manes/caffeine
|
||||
@ -237,11 +244,12 @@ dependencies {
|
||||
exclude("com.google.errorprone", "error_prone_annotations")
|
||||
}
|
||||
|
||||
|
||||
// https://github.com/MicroUtils/kotlin-logging
|
||||
implementation("io.github.microutils:kotlin-logging:1.8.3")
|
||||
implementation("io.github.microutils:kotlin-logging:2.0.3")
|
||||
implementation("org.slf4j:slf4j-api:1.7.30")
|
||||
|
||||
|
||||
|
||||
testImplementation("junit:junit:4.13")
|
||||
testImplementation("ch.qos.logback:logback-classic:1.2.3")
|
||||
}
|
||||
|
@ -1,919 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2020 Real Logic Limited.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// REMOVE WHEN ISSUE https://github.com/real-logic/aeron/issues/1057 is resolved!
|
||||
package io.aeron.driver.media;
|
||||
|
||||
import static io.aeron.driver.media.NetworkUtil.filterBySubnet;
|
||||
import static io.aeron.driver.media.NetworkUtil.findAddressOnInterface;
|
||||
import static io.aeron.driver.media.NetworkUtil.getProtocolFamily;
|
||||
import static java.lang.System.lineSeparator;
|
||||
import static java.net.InetAddress.getByAddress;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.agrona.BitUtil;
|
||||
import org.agrona.LangUtil;
|
||||
|
||||
import io.aeron.ChannelUri;
|
||||
import io.aeron.CommonContext;
|
||||
import io.aeron.driver.DefaultNameResolver;
|
||||
import io.aeron.driver.NameResolver;
|
||||
import io.aeron.driver.exceptions.InvalidChannelException;
|
||||
|
||||
/**
|
||||
* The media configuration for Aeron UDP channels as an instantiation of the socket addresses for a {@link ChannelUri}.
|
||||
*
|
||||
* @see ChannelUri
|
||||
* @see io.aeron.ChannelUriStringBuilder
|
||||
*/
|
||||
public final class UdpChannel
|
||||
{
|
||||
private static final AtomicInteger UNIQUE_CANONICAL_FORM_VALUE = new AtomicInteger();
|
||||
|
||||
private final boolean isManualControlMode;
|
||||
private final boolean isDynamicControlMode;
|
||||
private final boolean hasExplicitControl;
|
||||
private final boolean hasExplicitEndpoint;
|
||||
private final boolean isMulticast;
|
||||
private final boolean hasMulticastTtl;
|
||||
private final boolean hasTag;
|
||||
private final int multicastTtl;
|
||||
private final long tag;
|
||||
private final InetSocketAddress remoteData;
|
||||
private final InetSocketAddress localData;
|
||||
private final InetSocketAddress remoteControl;
|
||||
private final InetSocketAddress localControl;
|
||||
private final String uriStr;
|
||||
private final String canonicalForm;
|
||||
private final NetworkInterface localInterface;
|
||||
private final ProtocolFamily protocolFamily;
|
||||
private final ChannelUri channelUri;
|
||||
|
||||
private UdpChannel(final Context context)
|
||||
{
|
||||
isManualControlMode = context.isManualControlMode;
|
||||
isDynamicControlMode = context.isDynamicControlMode;
|
||||
hasExplicitEndpoint = context.hasExplicitEndpoint;
|
||||
hasExplicitControl = context.hasExplicitControl;
|
||||
isMulticast = context.isMulticast;
|
||||
hasTag = context.hasTagId;
|
||||
tag = context.tagId;
|
||||
hasMulticastTtl = context.hasMulticastTtl;
|
||||
multicastTtl = context.multicastTtl;
|
||||
remoteData = context.remoteData;
|
||||
localData = context.localData;
|
||||
remoteControl = context.remoteControl;
|
||||
localControl = context.localControl;
|
||||
uriStr = context.uriStr;
|
||||
canonicalForm = context.canonicalForm;
|
||||
localInterface = context.localInterface;
|
||||
protocolFamily = context.protocolFamily;
|
||||
channelUri = context.channelUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse channel URI and create a {@link UdpChannel}.
|
||||
*
|
||||
* @param channelUriString to parse.
|
||||
* @return a new {@link UdpChannel} as the result of parsing.
|
||||
* @throws InvalidChannelException if an error occurs.
|
||||
*/
|
||||
public static UdpChannel parse(final String channelUriString)
|
||||
{
|
||||
return parse(channelUriString, DefaultNameResolver.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse channel URI and create a {@link UdpChannel}.
|
||||
*
|
||||
* @param channelUriString to parse.
|
||||
* @param nameResolver to use for resolving names
|
||||
* @return a new {@link UdpChannel} as the result of parsing.
|
||||
* @throws InvalidChannelException if an error occurs.
|
||||
*/
|
||||
@SuppressWarnings("MethodLength")
|
||||
public static UdpChannel parse(final String channelUriString, final NameResolver nameResolver)
|
||||
{
|
||||
try
|
||||
{
|
||||
final ChannelUri channelUri = ChannelUri.parse(channelUriString);
|
||||
validateConfiguration(channelUri);
|
||||
|
||||
InetSocketAddress endpointAddress = getEndpointAddress(channelUri, nameResolver);
|
||||
final InetSocketAddress explicitControlAddress = getExplicitControlAddress(channelUri, nameResolver);
|
||||
|
||||
final String tagIdStr = channelUri.channelTag();
|
||||
final String controlMode = channelUri.get(CommonContext.MDC_CONTROL_MODE_PARAM_NAME);
|
||||
final boolean isManualControlMode = CommonContext.MDC_CONTROL_MODE_MANUAL.equals(controlMode);
|
||||
final boolean isDynamicControlMode = CommonContext.MDC_CONTROL_MODE_DYNAMIC.equals(controlMode);
|
||||
|
||||
final boolean requiresAdditionalSuffix =
|
||||
null == endpointAddress && null == explicitControlAddress ||
|
||||
(null != endpointAddress && endpointAddress.getPort() == 0) ||
|
||||
(null != explicitControlAddress && explicitControlAddress.getPort() == 0);
|
||||
|
||||
final boolean hasNoDistinguishingCharacteristic =
|
||||
null == endpointAddress && null == explicitControlAddress && null == tagIdStr;
|
||||
|
||||
if (isDynamicControlMode && null == explicitControlAddress)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"explicit control expected with dynamic control mode: " + channelUriString);
|
||||
}
|
||||
|
||||
if (hasNoDistinguishingCharacteristic && !isManualControlMode)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"URIs for UDP must specify an endpoint, control, tags, or control-mode=manual: " +
|
||||
channelUriString);
|
||||
}
|
||||
|
||||
if (null != endpointAddress && endpointAddress.isUnresolved())
|
||||
{
|
||||
throw new UnknownHostException("could not resolve endpoint address: " + endpointAddress);
|
||||
}
|
||||
|
||||
if (null != explicitControlAddress && explicitControlAddress.isUnresolved())
|
||||
{
|
||||
throw new UnknownHostException("could not resolve control address: " + explicitControlAddress);
|
||||
}
|
||||
|
||||
boolean hasExplicitEndpoint = true;
|
||||
if (null == endpointAddress)
|
||||
{
|
||||
hasExplicitEndpoint = false;
|
||||
if (explicitControlAddress == null || explicitControlAddress.getAddress() instanceof Inet4Address) {
|
||||
endpointAddress = new InetSocketAddress(InetAddress.getByAddress(null, new byte[]{0,0,0,0}), 0);
|
||||
} else {
|
||||
endpointAddress = new InetSocketAddress(InetAddress.getByAddress(null, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}),
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
final Context context = new Context()
|
||||
.uriStr(channelUriString)
|
||||
.channelUri(channelUri)
|
||||
.isManualControlMode(isManualControlMode)
|
||||
.isDynamicControlMode(isDynamicControlMode)
|
||||
.hasExplicitEndpoint(hasExplicitEndpoint)
|
||||
.hasNoDistinguishingCharacteristic(hasNoDistinguishingCharacteristic);
|
||||
|
||||
if (null != tagIdStr)
|
||||
{
|
||||
context.hasTagId(true).tagId(Long.parseLong(tagIdStr));
|
||||
}
|
||||
|
||||
if (endpointAddress.getAddress().isMulticastAddress())
|
||||
{
|
||||
final InetSocketAddress controlAddress = getMulticastControlAddress(endpointAddress);
|
||||
final InterfaceSearchAddress searchAddress = getInterfaceSearchAddress(channelUri);
|
||||
final NetworkInterface localInterface = findInterface(searchAddress);
|
||||
final InetSocketAddress resolvedAddress = resolveToAddressOfInterface(localInterface, searchAddress);
|
||||
|
||||
context
|
||||
.isMulticast(true)
|
||||
.localControlAddress(resolvedAddress)
|
||||
.remoteControlAddress(controlAddress)
|
||||
.localDataAddress(resolvedAddress)
|
||||
.remoteDataAddress(endpointAddress)
|
||||
.localInterface(localInterface)
|
||||
.protocolFamily(getProtocolFamily(endpointAddress.getAddress()))
|
||||
.canonicalForm(canonicalise(null, resolvedAddress, null, endpointAddress));
|
||||
|
||||
final String ttlValue = channelUri.get(CommonContext.TTL_PARAM_NAME);
|
||||
if (null != ttlValue)
|
||||
{
|
||||
context.hasMulticastTtl(true).multicastTtl(Integer.parseInt(ttlValue));
|
||||
}
|
||||
}
|
||||
else if (null != explicitControlAddress)
|
||||
{
|
||||
final String controlVal = channelUri.get(CommonContext.MDC_CONTROL_PARAM_NAME);
|
||||
final String endpointVal = channelUri.get(CommonContext.ENDPOINT_PARAM_NAME);
|
||||
|
||||
String suffix = "";
|
||||
if (requiresAdditionalSuffix)
|
||||
{
|
||||
suffix = (null != tagIdStr) ? "#" + tagIdStr : ("-" + UNIQUE_CANONICAL_FORM_VALUE.getAndAdd(1));
|
||||
}
|
||||
|
||||
final String canonicalForm = canonicalise(
|
||||
controlVal, explicitControlAddress, endpointVal, endpointAddress) + suffix;
|
||||
|
||||
context
|
||||
.hasExplicitControl(true)
|
||||
.remoteControlAddress(endpointAddress)
|
||||
.remoteDataAddress(endpointAddress)
|
||||
.localControlAddress(explicitControlAddress)
|
||||
.localDataAddress(explicitControlAddress)
|
||||
.protocolFamily(getProtocolFamily(endpointAddress.getAddress()))
|
||||
.canonicalForm(canonicalForm);
|
||||
}
|
||||
else
|
||||
{
|
||||
final InterfaceSearchAddress searchAddress = getInterfaceSearchAddress(channelUri);
|
||||
|
||||
final InetSocketAddress localAddress = searchAddress.getInetAddress().isAnyLocalAddress() ?
|
||||
searchAddress.getAddress() :
|
||||
resolveToAddressOfInterface(findInterface(searchAddress), searchAddress);
|
||||
|
||||
final String endpointVal = channelUri.get(CommonContext.ENDPOINT_PARAM_NAME);
|
||||
String suffix = "";
|
||||
if (requiresAdditionalSuffix)
|
||||
{
|
||||
suffix = (null != tagIdStr) ? "#" + tagIdStr : ("-" + UNIQUE_CANONICAL_FORM_VALUE.getAndAdd(1));
|
||||
}
|
||||
|
||||
context
|
||||
.remoteControlAddress(endpointAddress)
|
||||
.remoteDataAddress(endpointAddress)
|
||||
.localControlAddress(localAddress)
|
||||
.localDataAddress(localAddress)
|
||||
.protocolFamily(getProtocolFamily(endpointAddress.getAddress()))
|
||||
.canonicalForm(canonicalise(null, localAddress, endpointVal, endpointAddress) + suffix);
|
||||
}
|
||||
|
||||
return new UdpChannel(context);
|
||||
}
|
||||
catch (final Exception ex)
|
||||
{
|
||||
throw new InvalidChannelException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string which is a canonical form of the channel suitable for use as a file or directory
|
||||
* name and also as a method of hashing, etc.
|
||||
* <p>
|
||||
* The general format is:
|
||||
* UDP-interface:localPort-remoteAddress:remotePort
|
||||
*
|
||||
* @param localParamValue interface or MDC control param value or null for not set.
|
||||
* @param localData address/interface for the channel.
|
||||
* @param remoteParamValue endpoint param value or null if not set.
|
||||
* @param remoteData address for the channel.
|
||||
* @return canonical representation as a string.
|
||||
*/
|
||||
public static String canonicalise(
|
||||
final String localParamValue,
|
||||
final InetSocketAddress localData,
|
||||
final String remoteParamValue,
|
||||
final InetSocketAddress remoteData)
|
||||
{
|
||||
final StringBuilder builder = new StringBuilder(48);
|
||||
|
||||
builder.append("UDP-");
|
||||
|
||||
if (null == localParamValue)
|
||||
{
|
||||
builder.append(localData.getHostString())
|
||||
.append(':')
|
||||
.append(localData.getPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(localParamValue);
|
||||
}
|
||||
|
||||
builder.append('-');
|
||||
|
||||
if (null == remoteParamValue)
|
||||
{
|
||||
builder.append(remoteData.getHostString())
|
||||
.append(':')
|
||||
.append(remoteData.getPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(remoteParamValue);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote data address and port.
|
||||
*
|
||||
* @return remote data address and port.
|
||||
*/
|
||||
public InetSocketAddress remoteData()
|
||||
{
|
||||
return remoteData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local data address and port.
|
||||
*
|
||||
* @return local data address port.
|
||||
*/
|
||||
public InetSocketAddress localData()
|
||||
{
|
||||
return localData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote control address information
|
||||
*
|
||||
* @return remote control address information
|
||||
*/
|
||||
public InetSocketAddress remoteControl()
|
||||
{
|
||||
return remoteControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local control address and port.
|
||||
*
|
||||
* @return local control address and port.
|
||||
*/
|
||||
public InetSocketAddress localControl()
|
||||
{
|
||||
return localControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ChannelUri} for this channel.
|
||||
*
|
||||
* @return the {@link ChannelUri} for this channel.
|
||||
*/
|
||||
public ChannelUri channelUri()
|
||||
{
|
||||
return channelUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this channel got a multicast TTL value set so that {@link #multicastTtl()} is valid.
|
||||
*
|
||||
* @return true if this channel is a multicast TTL set otherwise false.
|
||||
*/
|
||||
public boolean hasMulticastTtl()
|
||||
{
|
||||
return hasMulticastTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multicast TTL value.
|
||||
*
|
||||
* @return multicast TTL value.
|
||||
*/
|
||||
public int multicastTtl()
|
||||
{
|
||||
return multicastTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* The canonical form for the channel
|
||||
* <p>
|
||||
* {@link UdpChannel#canonicalise}
|
||||
*
|
||||
* @return canonical form for channel.
|
||||
*/
|
||||
public String canonicalForm()
|
||||
{
|
||||
return canonicalForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link #canonicalForm()} for the channel.
|
||||
*
|
||||
* @return the {@link #canonicalForm()} for the channel.
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return canonicalForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the channel UDP multicast.
|
||||
*
|
||||
* @return true if the channel is UDP multicast.
|
||||
*/
|
||||
public boolean isMulticast()
|
||||
{
|
||||
return isMulticast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local interface to be used by the channel.
|
||||
*
|
||||
* @return {@link NetworkInterface} for the local interface used by the channel.
|
||||
*/
|
||||
public NetworkInterface localInterface()
|
||||
{
|
||||
return localInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original URI of the channel URI.
|
||||
*
|
||||
* @return the original uri string from the client.
|
||||
*/
|
||||
public String originalUriString()
|
||||
{
|
||||
return uriStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ProtocolFamily} for this channel.
|
||||
*
|
||||
* @return the {@link ProtocolFamily} for this channel.
|
||||
*/
|
||||
public ProtocolFamily protocolFamily()
|
||||
{
|
||||
return protocolFamily;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tag value on the channel which is only valid if {@link #hasTag()} is true.
|
||||
*
|
||||
* @return the tag value on the channel.
|
||||
*/
|
||||
public long tag()
|
||||
{
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the channel have manual control mode specified.
|
||||
*
|
||||
* @return does channel have manual control mode specified.
|
||||
*/
|
||||
public boolean isManualControlMode()
|
||||
{
|
||||
return isManualControlMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the channel have dynamic control mode specified.
|
||||
*
|
||||
* @return does channel have dynamic control mode specified.
|
||||
*/
|
||||
public boolean isDynamicControlMode()
|
||||
{
|
||||
return isDynamicControlMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the channel have an explicit endpoint address?
|
||||
*
|
||||
* @return does channel have an explicit endpoint address or not?
|
||||
*/
|
||||
public boolean hasExplicitEndpoint()
|
||||
{
|
||||
return hasExplicitEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the channel have an explicit control address as used with multi-destination-cast or not?
|
||||
*
|
||||
* @return does channel have an explicit control address or not?
|
||||
*/
|
||||
public boolean hasExplicitControl()
|
||||
{
|
||||
return hasExplicitControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the URI a tag to indicate entity relationships and if {@link #tag()} is valid.
|
||||
*
|
||||
* @return true if the channel has a tag.
|
||||
*/
|
||||
public boolean hasTag()
|
||||
{
|
||||
return hasTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the channel configured as multi-destination.
|
||||
*
|
||||
* @return true if he channel configured as multi-destination.
|
||||
*/
|
||||
public boolean isMultiDestination()
|
||||
{
|
||||
return isDynamicControlMode || isManualControlMode || hasExplicitControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this channel have a tag match to another channel including endpoints.
|
||||
*
|
||||
* @param udpChannel to match against.
|
||||
* @return true if there is a match otherwise false.
|
||||
*/
|
||||
public boolean matchesTag(final UdpChannel udpChannel)
|
||||
{
|
||||
if (!hasTag || !udpChannel.hasTag() || tag != udpChannel.tag())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (udpChannel.remoteData().getAddress().isAnyLocalAddress() &&
|
||||
udpChannel.remoteData().getPort() == 0 &&
|
||||
udpChannel.localData().getAddress().isAnyLocalAddress() &&
|
||||
udpChannel.localData().getPort() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"matching tag has set endpoint or control address - " + uriStr + " <> " + udpChannel.uriStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for debugging to get a human readable description of the channel.
|
||||
*
|
||||
* @return a human readable description of the channel.
|
||||
*/
|
||||
public String description()
|
||||
{
|
||||
final StringBuilder builder = new StringBuilder("UdpChannel - ");
|
||||
if (null != localInterface)
|
||||
{
|
||||
builder
|
||||
.append("interface: ")
|
||||
.append(localInterface.getDisplayName())
|
||||
.append(", ");
|
||||
}
|
||||
|
||||
builder
|
||||
.append("localData: ").append(localData)
|
||||
.append(", remoteData: ").append(remoteData)
|
||||
.append(", ttl: ").append(multicastTtl);
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Channels are considered equal if the {@link #canonicalForm()} is equal.
|
||||
*
|
||||
* @param o object to be compared with.
|
||||
* @return true if the {@link #canonicalForm()} is equal, otherwise false.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final UdpChannel that = (UdpChannel)o;
|
||||
|
||||
return Objects.equals(canonicalForm, that.canonicalForm);
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash code for the {@link #canonicalForm()}.
|
||||
*
|
||||
* @return the hash code for the {@link #canonicalForm()}.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return canonicalForm != null ? canonicalForm.hashCode() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the endpoint destination address from the URI.
|
||||
*
|
||||
* @param uri to check.
|
||||
* @param nameResolver to use for resolution
|
||||
* @return endpoint address for URI.
|
||||
*/
|
||||
public static InetSocketAddress destinationAddress(final ChannelUri uri, final NameResolver nameResolver)
|
||||
{
|
||||
try
|
||||
{
|
||||
validateConfiguration(uri);
|
||||
return getEndpointAddress(uri, nameResolver);
|
||||
}
|
||||
catch (final Exception ex)
|
||||
{
|
||||
throw new InvalidChannelException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve and endpoint into a {@link InetSocketAddress}.
|
||||
*
|
||||
* @param endpoint to resolve
|
||||
* @param uriParamName for the resolution
|
||||
* @param isReResolution for the resolution
|
||||
* @param nameResolver to be used for hostname.
|
||||
* @return address for endpoint
|
||||
* @throws UnknownHostException if the endpoint can not be resolved.
|
||||
*/
|
||||
public static InetSocketAddress resolve(
|
||||
final String endpoint, final String uriParamName, final boolean isReResolution, final NameResolver nameResolver)
|
||||
throws UnknownHostException
|
||||
{
|
||||
return SocketAddressParser.parse(endpoint, uriParamName, isReResolution, nameResolver);
|
||||
}
|
||||
|
||||
private static InetSocketAddress getMulticastControlAddress(final InetSocketAddress endpointAddress)
|
||||
throws UnknownHostException
|
||||
{
|
||||
final byte[] addressAsBytes = endpointAddress.getAddress().getAddress();
|
||||
validateDataAddress(addressAsBytes);
|
||||
|
||||
addressAsBytes[addressAsBytes.length - 1]++;
|
||||
return new InetSocketAddress(getByAddress(addressAsBytes), endpointAddress.getPort());
|
||||
}
|
||||
|
||||
private static InterfaceSearchAddress getInterfaceSearchAddress(final ChannelUri uri) throws UnknownHostException
|
||||
{
|
||||
final String interfaceValue = uri.get(CommonContext.INTERFACE_PARAM_NAME);
|
||||
if (null != interfaceValue)
|
||||
{
|
||||
return InterfaceSearchAddress.parse(interfaceValue);
|
||||
}
|
||||
|
||||
return InterfaceSearchAddress.wildcard();
|
||||
}
|
||||
|
||||
private static InetSocketAddress getEndpointAddress(final ChannelUri uri, final NameResolver nameResolver)
|
||||
{
|
||||
InetSocketAddress address = null;
|
||||
final String endpointValue = uri.get(CommonContext.ENDPOINT_PARAM_NAME);
|
||||
if (null != endpointValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
address = SocketAddressParser.parse(
|
||||
endpointValue, CommonContext.ENDPOINT_PARAM_NAME, false, nameResolver);
|
||||
}
|
||||
catch (final UnknownHostException ex)
|
||||
{
|
||||
LangUtil.rethrowUnchecked(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
private static InetSocketAddress getExplicitControlAddress(final ChannelUri uri, final NameResolver nameResolver)
|
||||
{
|
||||
InetSocketAddress address = null;
|
||||
final String controlValue = uri.get(CommonContext.MDC_CONTROL_PARAM_NAME);
|
||||
if (null != controlValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
address = SocketAddressParser.parse(
|
||||
controlValue, CommonContext.MDC_CONTROL_PARAM_NAME, false, nameResolver);
|
||||
}
|
||||
catch (final UnknownHostException ex)
|
||||
{
|
||||
LangUtil.rethrowUnchecked(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
private static void validateDataAddress(final byte[] addressAsBytes)
|
||||
{
|
||||
if (BitUtil.isEven(addressAsBytes[addressAsBytes.length - 1]))
|
||||
{
|
||||
throw new IllegalArgumentException("multicast data address must be odd");
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateConfiguration(final ChannelUri uri)
|
||||
{
|
||||
validateMedia(uri);
|
||||
}
|
||||
|
||||
private static void validateMedia(final ChannelUri uri)
|
||||
{
|
||||
if (!uri.isUdp())
|
||||
{
|
||||
throw new IllegalArgumentException("UdpChannel only supports UDP media: " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
private static InetSocketAddress resolveToAddressOfInterface(
|
||||
final NetworkInterface localInterface, final InterfaceSearchAddress searchAddress)
|
||||
{
|
||||
final InetAddress interfaceAddress = findAddressOnInterface(
|
||||
localInterface, searchAddress.getInetAddress(), searchAddress.getSubnetPrefix());
|
||||
|
||||
if (null == interfaceAddress)
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
return new InetSocketAddress(interfaceAddress, searchAddress.getPort());
|
||||
}
|
||||
|
||||
private static NetworkInterface findInterface(final InterfaceSearchAddress searchAddress)
|
||||
throws SocketException
|
||||
{
|
||||
final NetworkInterface[] filteredInterfaces = filterBySubnet(
|
||||
searchAddress.getInetAddress(), searchAddress.getSubnetPrefix());
|
||||
|
||||
for (final NetworkInterface networkInterface : filteredInterfaces)
|
||||
{
|
||||
if (networkInterface.supportsMulticast() || networkInterface.isLoopback())
|
||||
{
|
||||
return networkInterface;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(errorNoMatchingInterfaces(filteredInterfaces, searchAddress));
|
||||
}
|
||||
|
||||
private static String errorNoMatchingInterfaces(
|
||||
final NetworkInterface[] filteredInterfaces, final InterfaceSearchAddress address)
|
||||
throws SocketException
|
||||
{
|
||||
final StringBuilder builder = new StringBuilder()
|
||||
.append("Unable to find multicast interface matching criteria: ")
|
||||
.append(address.getAddress())
|
||||
.append('/')
|
||||
.append(address.getSubnetPrefix());
|
||||
|
||||
if (filteredInterfaces.length > 0)
|
||||
{
|
||||
builder.append(lineSeparator()).append(" Candidates:");
|
||||
|
||||
for (final NetworkInterface ifc : filteredInterfaces)
|
||||
{
|
||||
builder
|
||||
.append(lineSeparator())
|
||||
.append(" - Name: ")
|
||||
.append(ifc.getDisplayName())
|
||||
.append(", addresses: ")
|
||||
.append(ifc.getInterfaceAddresses())
|
||||
.append(", multicast: ")
|
||||
.append(ifc.supportsMulticast());
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
static class Context
|
||||
{
|
||||
long tagId;
|
||||
int multicastTtl;
|
||||
InetSocketAddress remoteData;
|
||||
InetSocketAddress localData;
|
||||
InetSocketAddress remoteControl;
|
||||
InetSocketAddress localControl;
|
||||
String uriStr;
|
||||
String canonicalForm;
|
||||
NetworkInterface localInterface;
|
||||
ProtocolFamily protocolFamily;
|
||||
ChannelUri channelUri;
|
||||
boolean isManualControlMode = false;
|
||||
boolean isDynamicControlMode = false;
|
||||
boolean hasExplicitEndpoint = false;
|
||||
boolean hasExplicitControl = false;
|
||||
boolean isMulticast = false;
|
||||
boolean hasMulticastTtl = false;
|
||||
boolean hasTagId = false;
|
||||
boolean hasNoDistinguishingCharacteristic = false;
|
||||
|
||||
Context uriStr(final String uri)
|
||||
{
|
||||
uriStr = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context remoteDataAddress(final InetSocketAddress remoteData)
|
||||
{
|
||||
this.remoteData = remoteData;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context localDataAddress(final InetSocketAddress localData)
|
||||
{
|
||||
this.localData = localData;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context remoteControlAddress(final InetSocketAddress remoteControl)
|
||||
{
|
||||
this.remoteControl = remoteControl;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context localControlAddress(final InetSocketAddress localControl)
|
||||
{
|
||||
this.localControl = localControl;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context canonicalForm(final String canonicalForm)
|
||||
{
|
||||
this.canonicalForm = canonicalForm;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context localInterface(final NetworkInterface networkInterface)
|
||||
{
|
||||
this.localInterface = networkInterface;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context protocolFamily(final ProtocolFamily protocolFamily)
|
||||
{
|
||||
this.protocolFamily = protocolFamily;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context hasMulticastTtl(final boolean hasMulticastTtl)
|
||||
{
|
||||
this.hasMulticastTtl = hasMulticastTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context multicastTtl(final int multicastTtl)
|
||||
{
|
||||
this.multicastTtl = multicastTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context tagId(final long tagId)
|
||||
{
|
||||
this.tagId = tagId;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context channelUri(final ChannelUri channelUri)
|
||||
{
|
||||
this.channelUri = channelUri;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context isManualControlMode(final boolean isManualControlMode)
|
||||
{
|
||||
this.isManualControlMode = isManualControlMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context isDynamicControlMode(final boolean isDynamicControlMode)
|
||||
{
|
||||
this.isDynamicControlMode = isDynamicControlMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context hasExplicitEndpoint(final boolean hasExplicitEndpoint)
|
||||
{
|
||||
this.hasExplicitEndpoint = hasExplicitEndpoint;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context hasExplicitControl(final boolean hasExplicitControl)
|
||||
{
|
||||
this.hasExplicitControl = hasExplicitControl;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context isMulticast(final boolean isMulticast)
|
||||
{
|
||||
this.isMulticast = isMulticast;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context hasTagId(final boolean hasTagId)
|
||||
{
|
||||
this.hasTagId = hasTagId;
|
||||
return this;
|
||||
}
|
||||
|
||||
Context hasNoDistinguishingCharacteristic(final boolean hasNoDistinguishingCharacteristic)
|
||||
{
|
||||
this.hasNoDistinguishingCharacteristic = hasNoDistinguishingCharacteristic;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user