All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.aeron.protocol.ResolutionEntryFlyweight Maven / Gradle / Ivy

There is a newer version: 1.46.7
Show newest version
/*
 * Copyright 2014-2021 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.
 */
package io.aeron.protocol;

import org.agrona.LangUtil;
import org.agrona.concurrent.UnsafeBuffer;

import java.nio.ByteBuffer;

import static java.lang.Integer.toHexString;
import static java.nio.ByteOrder.LITTLE_ENDIAN;
import static org.agrona.BitUtil.*;

/**
 * Flyweight for Resolution Entry header.
 * 

* Protocol Specification * wiki page. */ public class ResolutionEntryFlyweight extends HeaderFlyweight { /** * Resolution type field flag for IPv4. */ public static final byte RES_TYPE_NAME_TO_IP4_MD = 0x01; /** * Resolution type field flag for IPv6. */ public static final byte RES_TYPE_NAME_TO_IP6_MD = 0x02; /** * Length of an IPv4 address in bytes. */ public static final int ADDRESS_LENGTH_IP4 = 4; /** * Length of an IPv6 address in bytes. */ public static final int ADDRESS_LENGTH_IP6 = 16; /** * (S) - Self flag */ public static final short SELF_FLAG = 0x80; /** * Offset in the frame at which the res-type (resolution type) field begins. */ public static final int RES_TYPE_FIELD_OFFSET = 0; /** * Offset in the frame at which the res-flags field begins. */ public static final int RES_FLAGS_FIELD_OFFSET = 1; /** * Offset in the frame at which the UDP port field begins. */ public static final int UDP_PORT_FIELD_OFFSET = 2; /** * Offset in the frame at which the age field begins. */ public static final int AGE_IN_MS_FIELD_OFFSET = 4; /** * Offset in the frame at which the IP address field begins. */ public static final int ADDRESS_FIELD_OFFSET = 8; /** * Maximum length allowed for a name. */ public static final int MAX_NAME_LENGTH = 512; /** * Default constructor which can later be used to wrap a frame. */ public ResolutionEntryFlyweight() { } /** * Construct the flyweight over a frame. * * @param buffer containing the frame. */ public ResolutionEntryFlyweight(final UnsafeBuffer buffer) { super(buffer); } /** * Construct the flyweight over a frame. * * @param buffer containing the frame. */ public ResolutionEntryFlyweight(final ByteBuffer buffer) { super(buffer); } /** * Set the protocol type of the resolution. * * @param type of the resolution entry protocol. * @return this for a fluent API. * @see #RES_TYPE_NAME_TO_IP4_MD * @see #RES_TYPE_NAME_TO_IP4_MD */ public ResolutionEntryFlyweight resType(final byte type) { putByte(RES_TYPE_FIELD_OFFSET, type); return this; } /** * Get the protocol type of the resolution entry. * * @return the protocol type of the resolution entry. * @see #RES_TYPE_NAME_TO_IP4_MD * @see #RES_TYPE_NAME_TO_IP4_MD */ public byte resType() { return getByte(RES_TYPE_FIELD_OFFSET); } /** * Set the flags for the resolution entry. * * @param flags field value. * @return this for a fluent API. * @see #SELF_FLAG */ public ResolutionEntryFlyweight flags(final short flags) { putByte(RES_FLAGS_FIELD_OFFSET, (byte)flags); return this; } /** * Get the flags for the resolution entry. * * @return the flags for the resolution entry. */ public short flags() { return (short)(getByte(RES_FLAGS_FIELD_OFFSET) & 0xFF); } /** * Set the UDP port of the resolver with a given name. * * @param udpPort of the resolver with a given name. * @return this for a fluent API. */ public ResolutionEntryFlyweight udpPort(final int udpPort) { putShort(UDP_PORT_FIELD_OFFSET, (short)udpPort, LITTLE_ENDIAN); return this; } /** * Get the UDP port of the resolver with a given name. * * @return the UDP port of the resolver with a given name. */ public int udpPort() { return getShort(UDP_PORT_FIELD_OFFSET, LITTLE_ENDIAN) & 0xFFFF; } /** * Set the age of the entry based on last observed activity. * * @param ageInMs of the entry based on last observed activity. * @return this for a fluent API. */ public ResolutionEntryFlyweight ageInMs(final int ageInMs) { putInt(AGE_IN_MS_FIELD_OFFSET, ageInMs, LITTLE_ENDIAN); return this; } /** * Get the age of the entry based on last observed activity. * * @return the age of the entry based on last observed activity. */ public int ageInMs() { return getInt(AGE_IN_MS_FIELD_OFFSET, LITTLE_ENDIAN); } /** * Put the address into the resolution entry. It must come after calling {@link #resType(byte)}. * * @param address to be written for the resolution entry. * @return this for a fluent API. */ public ResolutionEntryFlyweight putAddress(final byte[] address) { switch (resType()) { case RES_TYPE_NAME_TO_IP4_MD: if (ADDRESS_LENGTH_IP4 != address.length) { throw new IllegalArgumentException("Invalid address length: " + address.length); } putBytes(ADDRESS_FIELD_OFFSET, address, 0, ADDRESS_LENGTH_IP4); break; case RES_TYPE_NAME_TO_IP6_MD: if (ADDRESS_LENGTH_IP6 != address.length) { throw new IllegalArgumentException("Invalid address length: " + address.length); } putBytes(ADDRESS_FIELD_OFFSET, address, 0, ADDRESS_LENGTH_IP6); break; default: throw new IllegalStateException("unknown RES_TYPE=" + resType()); } return this; } /** * Get the address for the entry by copying it into the destination buffer. * * @param dstBuffer into which the address will be copied. * @return length of the address copied. */ public int getAddress(final byte[] dstBuffer) { switch (resType()) { case RES_TYPE_NAME_TO_IP4_MD: if (ADDRESS_LENGTH_IP4 > dstBuffer.length) { throw new IllegalArgumentException("Insufficient length: " + dstBuffer.length); } getBytes(ADDRESS_FIELD_OFFSET, dstBuffer, 0, ADDRESS_LENGTH_IP4); return ADDRESS_LENGTH_IP4; case RES_TYPE_NAME_TO_IP6_MD: if (ADDRESS_LENGTH_IP6 > dstBuffer.length) { throw new IllegalArgumentException("Insufficient length: " + dstBuffer.length); } getBytes(ADDRESS_FIELD_OFFSET, dstBuffer, 0, ADDRESS_LENGTH_IP6); return ADDRESS_LENGTH_IP6; } throw new IllegalStateException("unknown RES_TYPE=" + resType()); } /** * Append the address to the provided {@link Appendable} in ASCII format. * * @param appendable to which the address will be appended. */ public void appendAddress(final Appendable appendable) { try { switch (resType()) { case RES_TYPE_NAME_TO_IP4_MD: { final int i = ADDRESS_FIELD_OFFSET; appendable .append(String.valueOf(getByte(i) & 0xFF)) .append('.') .append(String.valueOf(getByte(i + 1) & 0xFF)) .append('.') .append(String.valueOf(getByte(i + 2) & 0xFF)) .append('.') .append(String.valueOf(getByte(i + 3) & 0xFF)); break; } case RES_TYPE_NAME_TO_IP6_MD: { final int i = ADDRESS_FIELD_OFFSET; appendable .append(toHexString(((getByte(i) << 8) & 0xFF00) | getByte(i + 1) & 0xFF)) .append(':') .append(toHexString(((getByte(i + 2) << 8) & 0xFF00) | getByte(i + 3) & 0xFF)) .append(':') .append(toHexString(((getByte(i + 4) << 8) & 0xFF00) | getByte(i + 5) & 0xFF)) .append(':') .append(toHexString(((getByte(i + 6) << 8) & 0xFF00) | getByte(i + 7) & 0xFF)) .append(':') .append(toHexString(((getByte(i + 8) << 8) & 0xFF00) | getByte(i + 9) & 0xFF)) .append(':') .append(toHexString(((getByte(i + 10) << 8) & 0xFF00) | getByte(i + 11) & 0xFF)) .append(':') .append(toHexString(((getByte(i + 12) << 8) & 0xFF00) | getByte(i + 13) & 0xFF)) .append(':') .append(toHexString(((getByte(i + 14) << 8) & 0xFF00) | getByte(i + 15) & 0xFF)); break; } default: appendable.append("unknown RES_TYPE=").append(String.valueOf(resType())); } } catch (final Exception ex) { LangUtil.rethrowUnchecked(ex); } } /** * Put the name for the resolution entry into the frame. * * @param name for the resolution entry. * @return this for a fluent API. */ public ResolutionEntryFlyweight putName(final byte[] name) { final int nameOffset = nameOffset(resType()); putShort(nameOffset, (short)name.length, LITTLE_ENDIAN); putBytes(nameOffset + SIZE_OF_SHORT, name); return this; } /** * Get the name for the entry by copying it into the destination buffer. * * @param dstBuffer into which the name will be copied. * @return the number of bytes copied. */ public int getName(final byte[] dstBuffer) { final int nameOffset = nameOffset(resType()); final short nameLength = getShort(nameOffset, LITTLE_ENDIAN); if (nameLength > dstBuffer.length) { throw new IllegalArgumentException("Insufficient length: " + dstBuffer.length); } getBytes(nameOffset + SIZE_OF_SHORT, dstBuffer, 0, nameLength); return nameLength; } /** * Append the name to the provided {@link Appendable} in ASCII format. * * @param appendable to which the name will be appended. */ public void appendName(final StringBuilder appendable) { final int nameOffset = nameOffset(resType()); final short nameLength = getShort(nameOffset, LITTLE_ENDIAN); getStringWithoutLengthAscii(nameOffset + SIZE_OF_SHORT, nameLength, appendable); } /** * Total length of the entry in bytes. * * @return total length of the entry in bytes. */ public int entryLength() { final int nameOffset = nameOffset(resType()); return align(nameOffset + SIZE_OF_SHORT + getShort(nameOffset, LITTLE_ENDIAN), SIZE_OF_LONG); } /** * Offset in the entry at which the name begins depending on resolution type. * * @param resType for the protocol family. * @return offset in the entry at which the name field begins. */ public static int nameOffset(final byte resType) { switch (resType) { case RES_TYPE_NAME_TO_IP4_MD: return ADDRESS_FIELD_OFFSET + ADDRESS_LENGTH_IP4; case RES_TYPE_NAME_TO_IP6_MD: return ADDRESS_FIELD_OFFSET + ADDRESS_LENGTH_IP6; } throw new IllegalStateException("unknown RES_TYPE=" + resType); } /** * Calculate the length required for the entry when encoded. * * @param resType of the entry. * @param nameLength of the name in the entry. * @return the required length of the entry in bytes. */ public static int entryLengthRequired(final byte resType, final int nameLength) { return align(nameOffset(resType) + SIZE_OF_SHORT + nameLength, SIZE_OF_LONG); } /** * Get the length of the address given a resolution type. * * @param resType to lookup address length for. * @return the length of the address given a resolution type. */ public static int addressLength(final byte resType) { switch (resType) { case RES_TYPE_NAME_TO_IP4_MD: return ADDRESS_LENGTH_IP4; case RES_TYPE_NAME_TO_IP6_MD: return ADDRESS_LENGTH_IP6; } throw new IllegalStateException("unknown RES_TYPE=" + resType); } /** * Is the local address a match for binding a socket to ANY IP. * * @param address to check which can be IPv4 or IPv6. * @param addressLength of the address in bytes. * @return true if address is an ANY match otherwise false. */ public static boolean isAnyLocalAddress(final byte[] address, final int addressLength) { if (addressLength == ADDRESS_LENGTH_IP4) { return 0 == address[0] && 0 == address[1] && 0 == address[2] && 0 == address[3]; } else if (addressLength == ADDRESS_LENGTH_IP6) { byte val = 0; for (int i = 0; i < ADDRESS_LENGTH_IP6; i++) { val |= address[i]; } return 0 == val; } return false; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy