/* * Copyright 2013 Thomas Bocek * * 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 * * http://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 net.tomp2p.peers; import io.netty.buffer.ByteBuf; import java.io.Serializable; import java.net.Inet4Address; import java.net.InetAddress; import net.tomp2p.utils.Utils; /** * A PeerSocketAddress includes always both ports, UDP and TCP. * * @author Thomas Bocek * */ public class PeerSocketAddress implements Serializable { private static final long serialVersionUID = 8483270473601620720L; private final InetAddress inetAddress; private final int tcpPort; private final int udpPort; private final int offset; /** * Creates a new PeerSocketAddress including both UDP and TCP ports. * * @param inetAddress * The InetAddress of the peer. Can be IPv6 or IPv4 * @param tcpPort * The TCP port * @param udpPort * The UDP port */ public PeerSocketAddress(final InetAddress inetAddress, final int tcpPort, final int udpPort) { this(inetAddress, tcpPort, udpPort, -1); } /** * Creates a new PeerSocketAddress including both UDP and TCP ports. This is used mostly internally as the offset is * stored as well. * * @param inetAddress * The InetAddress of the peer. Can be IPv6 or IPv4 * @param tcpPort * The TCP port * @param udpPort * The UDP port * @param offset * The offset that we processed */ public PeerSocketAddress(final InetAddress inetAddress, final int tcpPort, final int udpPort, final int offset) { this.inetAddress = inetAddress; this.tcpPort = tcpPort; this.udpPort = udpPort; this.offset = offset; } /** * @return The IPv4 or IPv6 address. */ public InetAddress getInetAddress() { return inetAddress; } /** * @return The TCP port. */ public int getTcpPort() { return tcpPort; } /** * @return The UDP port. */ public int getUdpPort() { return udpPort; } /** * @return Returns the offset. */ public int getOffset() { return offset; } /** * Serializes a peer socket address to a byte array. First the ports are serialized: TCP and UDP, then the address. * * @param me * The byte array to store the serialization * @param offset * The offset where to start * @return How many data have been written */ public int toByteArray(final byte[] me, final int offset) { int offset2 = offset; me[offset2++] = (byte) (tcpPort >>> Utils.BYTE_BITS); me[offset2++] = (byte) tcpPort; me[offset2++] = (byte) (udpPort >>> Utils.BYTE_BITS); me[offset2++] = (byte) udpPort; if (inetAddress instanceof Inet4Address) { System.arraycopy(inetAddress.getAddress(), 0, me, offset2, Utils.IPV4_BYTES); offset2 += Utils.IPV4_BYTES; } else { System.arraycopy(inetAddress.getAddress(), 0, me, offset2, Utils.IPV6_BYTES); offset2 += Utils.IPV6_BYTES; } return offset2; } @Override public String toString() { StringBuilder sb = new StringBuilder("PSA["); sb.append(inetAddress).append(",t:").append(tcpPort).append(",u:").append(udpPort).append("]"); return sb.toString(); } /** * Converts an byte array into a peer socket address. * * @param me * The byte array * @param isIPv4 * Indicates if its IPv4 or IPv6 * @param offsetOriginal * The offset where to start reading in the array * @return the PeerSocketAddress and the new offset */ public static PeerSocketAddress create(final byte[] me, final boolean isIPv4, final int offsetOriginal) { int offset = offsetOriginal; final int portTCP = ((me[offset++] & Utils.MASK_FF) << Utils.BYTE_BITS) + (me[offset++] & Utils.MASK_FF); final int portUDP = ((me[offset++] & Utils.MASK_FF) << Utils.BYTE_BITS) + (me[offset++] & Utils.MASK_FF); // final InetAddress address; if (isIPv4) { address = Utils.inet4FromBytes(me, offset); // IPv4 is 32 bit offset += Utils.IPV4_BYTES; } else { address = Utils.inet6FromBytes(me, offset); // IPv6 is 128 bit offset += Utils.IPV6_BYTES; } return new PeerSocketAddress(address, portTCP, portUDP, offset); } /** * Converts an ChannelBuffer into a peer socket address. * * @param ch * The channel buffer * @param isIPv4 * if the IP is v4 or v6 * @return the PeerSocketAddress and the new offset */ public static PeerSocketAddress create(final ByteBuf ch, final boolean isIPv4) { final int portTCP = ch.readUnsignedShort(); final int portUDP = ch.readUnsignedShort(); // final InetAddress address; final byte[] me; if (isIPv4) { // IPv4 is 32 bit me = new byte[Utils.IPV4_BYTES]; ch.readBytes(me); address = Utils.inet4FromBytes(me, 0); } else { // IPv6 is 128 bit me = new byte[Utils.IPV6_BYTES]; ch.readBytes(me); address = Utils.inet6FromBytes(me, 0); } return new PeerSocketAddress(address, portTCP, portUDP, ch.readerIndex()); } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj instanceof PeerSocketAddress) { PeerSocketAddress psa = (PeerSocketAddress) obj; return psa.inetAddress.equals(inetAddress) && psa.tcpPort == tcpPort && psa.udpPort == udpPort; } else { return false; } } @Override public int hashCode() { return inetAddress.hashCode() ^ tcpPort ^ udpPort; } }