package net.tomp2p.peers;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import io.netty.buffer.ByteBuf;
import lombok.Builder;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.Wither;
import net.tomp2p.peers.IP.IPv4;
import net.tomp2p.peers.IP.IPv6;
import net.tomp2p.utils.Pair;
import net.tomp2p.utils.Utils;
public abstract class PeerSocketAddress {
public final static int PORT_SIZE = 6;
public abstract int size();
public abstract int encode(final byte[] array, int offset);
public abstract int encode(final byte[] array, int offset, boolean skipAddress);
public abstract PeerSocketAddress encode(final ByteBuf buf);
public abstract PeerSocketAddress encode(final ByteBuf buf, boolean skipAddress);
public abstract String toString();
@Builder
@Accessors(fluent = true, chain = true)
public static class PeerSocket4Address extends PeerSocketAddress {
//ports + ip size
public final static int SIZE = PORT_SIZE + 4;
@Getter @Wither final private IPv4 ipv4;
@Getter @Wither final private int udpPort;
@Getter @Wither final private int tcpPort;
@Getter @Wither final private int udtPort;
public static Pair<PeerSocket4Address, Integer> decode(final byte[] array, int offset) {
return decode(array, offset, false);
}
public static Pair<PeerSocket4Address, Integer> decode(final byte[] array, int offset, final boolean skipAddress) {
PeerSocket4AddressBuilder builder = new PeerSocket4AddressBuilder();
if(!skipAddress) {
final int ip = Utils.byteArrayToInt(array, offset);
offset +=4;
builder.ipv4(IPv4.fromInt(ip));
}
final int udpPort = Utils.byteArrayToShort(array, offset);
offset +=2;
final int tcpPort = Utils.byteArrayToShort(array, offset);
offset +=2;
final int udtPort = Utils.byteArrayToShort(array, offset);
offset +=2;
return new Pair<PeerSocket4Address, Integer> (
builder.udpPort(udpPort)
.tcpPort(tcpPort)
.udtPort(udtPort)
.build(), offset);
}
public static PeerSocket4Address decode(ByteBuf buf) {
return decode(buf, false);
}
public static PeerSocket4Address decode(ByteBuf buf, final boolean skipAddress) {
PeerSocket4AddressBuilder builder = new PeerSocket4AddressBuilder();
if(!skipAddress) {
builder.ipv4(IPv4.fromInt(buf.readInt()));
}
return builder.udpPort(buf.readUnsignedShort())
.tcpPort(buf.readUnsignedShort())
.udtPort(buf.readUnsignedShort())
.build();
}
@Override
public int encode(final byte[] array, int offset) {
return encode(array, offset, false);
}
@Override
public int encode(final byte[] array, int offset, final boolean skipAddress) {
if(!skipAddress) {
offset = Utils.intToByteArray(ipv4.toInt(), array, offset);
}
offset = Utils.shortToByteArray(udpPort, array, offset);
offset = Utils.shortToByteArray(tcpPort, array, offset);
offset = Utils.shortToByteArray(udtPort, array, offset);
return offset;
}
@Override
public PeerSocket4Address encode(final ByteBuf buf) {
return encode(buf, false);
}
@Override
public PeerSocket4Address encode(final ByteBuf buf, final boolean skipAddress) {
if(!skipAddress) {
buf.writeInt(ipv4.toInt());
}
buf.writeShort(udpPort);
buf.writeShort(tcpPort);
buf.writeShort(udtPort);
return this;
}
public InetSocketAddress createUDPSocket() {
return new InetSocketAddress(ipv4.toInetAddress(), udpPort);
}
public InetSocketAddress createTCPSocket() {
return new InetSocketAddress(ipv4.toInetAddress(), tcpPort);
}
public InetSocketAddress createUDTSocket() {
return new InetSocketAddress(ipv4.toInetAddress(), udtPort);
}
public InetSocketAddress createSocket(int port) {
return new InetSocketAddress(ipv4.toInetAddress(), port);
}
@Override
public int size() {
return SIZE;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
return sb.append(ipv4)
.append(":t")
.append(tcpPort)
.append("/u")
.append(udpPort)
.append("/d")
.append(udtPort).toString();
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof PeerSocket4Address)) {
return false;
}
if (this == obj) {
return true;
}
final PeerSocket4Address psa = (PeerSocket4Address) obj;
return Utils.equals(psa.ipv4, ipv4)
&& psa.tcpPort == tcpPort
&& psa.udpPort == udpPort
&& psa.udtPort == udtPort;
}
public boolean equalsWithoutPorts(final Object obj) {
if (!(obj instanceof PeerSocket4Address)) {
return false;
}
if (this == obj) {
return true;
}
final PeerSocket4Address psa = (PeerSocket4Address) obj;
return Utils.equals(psa.ipv4, ipv4);
}
@Override
public int hashCode() {
return Utils.hashCode(ipv4) ^ (tcpPort << 16) ^ udpPort ^ udtPort;
}
public static PeerSocket4Address create(Inet4Address inet, int udpPort, int tcpPort, int udtPort) {
return PeerSocket4Address.builder().ipv4(IPv4.fromInet4Address(inet)).udpPort(udpPort).tcpPort(tcpPort).udtPort(udtPort).build();
}
}
@Builder
@Accessors(fluent = true, chain = true)
public static class PeerSocket6Address extends PeerSocketAddress {
//ports + ip size
public final static int SIZE = PORT_SIZE + 16;
@Getter @Wither final private IPv6 ipv6;
@Getter @Wither final private int udpPort;
@Getter @Wither final private int tcpPort;
@Getter @Wither final private int udtPort;
public static Pair<PeerSocket6Address, Integer> decode(final byte[] array, int offset) {
return decode(array, offset, false);
}
public static Pair<PeerSocket6Address, Integer> decode(final byte[] array, int offset, final boolean skipAddress) {
PeerSocket6AddressBuilder builder = new PeerSocket6AddressBuilder();
if(!skipAddress) {
final long hi = Utils.byteArrayToLong(array, offset);
offset +=8;
final long lo = Utils.byteArrayToLong(array, offset);
offset +=8;
builder.ipv6(IPv6.fromLong(hi, lo));
}
final int udpPort = Utils.byteArrayToShort(array, offset);
offset +=2;
final int tcpPort = Utils.byteArrayToShort(array, offset);
offset +=2;
final int udtPort = Utils.byteArrayToShort(array, offset);
offset +=2;
return new Pair<PeerSocket6Address, Integer> (
builder.udpPort(udpPort)
.tcpPort(tcpPort)
.udtPort(udtPort)
.build(), offset);
}
public static PeerSocket6Address decode(ByteBuf buf) {
return decode(buf, false);
}
public static PeerSocket6Address decode(ByteBuf buf, final boolean skipAddress) {
PeerSocket6AddressBuilder builder = new PeerSocket6AddressBuilder();
if(!skipAddress) {
builder.ipv6(IPv6.fromLong(buf.readLong(),buf.readLong()));
}
return builder.udpPort(buf.readUnsignedShort())
.tcpPort(buf.readUnsignedShort())
.udtPort(buf.readUnsignedShort())
.build();
}
@Override
public int encode(final byte[] array, int offset) {
return encode(array, offset, false);
}
@Override
public int encode(final byte[] array, int offset, final boolean skipAddress) {
if(!skipAddress) {
offset = Utils.longToByteArray(ipv6.toLongHi(), ipv6.toLongLo(), array, offset);
}
offset = Utils.shortToByteArray(udpPort, array, offset);
offset = Utils.shortToByteArray(tcpPort, array, offset);
offset = Utils.shortToByteArray(udtPort, array, offset);
return offset;
}
@Override
public PeerSocket6Address encode(final ByteBuf buf) {
return encode(buf, false);
}
@Override
public PeerSocket6Address encode(final ByteBuf buf, final boolean skipAddress) {
if(!skipAddress) {
buf.writeLong(ipv6.toLongHi());
buf.writeLong(ipv6.toLongLo());
}
buf.writeShort(udpPort);
buf.writeShort(tcpPort);
buf.writeShort(udtPort);
return this;
}
public InetSocketAddress createUDPSocket() {
return new InetSocketAddress(ipv6.toInetAddress(), udpPort);
}
public InetSocketAddress createTCPSocket() {
return new InetSocketAddress(ipv6.toInetAddress(), tcpPort);
}
public InetSocketAddress createUDTSocket() {
return new InetSocketAddress(ipv6.toInetAddress(), udtPort);
}
public InetSocketAddress createSocket(int port) {
return new InetSocketAddress(ipv6.toInetAddress(), port);
}
@Override
public int size() {
return SIZE;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
return sb.append(ipv6)
.append(":t")
.append(tcpPort)
.append("/u")
.append(udpPort)
.append("/d")
.append(udtPort).toString();
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof PeerSocket6Address)) {
return false;
}
if (this == obj) {
return true;
}
final PeerSocket6Address psa = (PeerSocket6Address) obj;
return Utils.equals(psa.ipv6, ipv6)
&& psa.tcpPort == tcpPort
&& psa.udpPort == udpPort
&& psa.udtPort == udtPort;
}
public boolean equalsWithoutPorts(final Object obj) {
if (!(obj instanceof PeerSocket6Address)) {
return false;
}
if (this == obj) {
return true;
}
final PeerSocket6Address psa = (PeerSocket6Address) obj;
return Utils.equals(psa.ipv6, ipv6);
}
@Override
public int hashCode() {
return Utils.hashCode(ipv6) ^ (tcpPort << 16) ^ udpPort ^ udtPort;
}
}
public InetSocketAddress createTCPSocket() {
if(this instanceof PeerSocket4Address) {
return ((PeerSocket4Address)this).createTCPSocket();
} else {
return ((PeerSocket6Address)this).createTCPSocket();
}
}
public static PeerSocketAddress create(InetAddress inet, int udpPort, int tcpPort, int udtPort) {
if(inet instanceof Inet4Address) {
return PeerSocket4Address.builder().ipv4(IPv4.fromInet4Address(inet)).udpPort(udpPort).tcpPort(tcpPort).udtPort(udtPort).build();
} else {
return PeerSocket6Address.builder().ipv6(IPv6.fromInet6Address(inet)).udpPort(udpPort).tcpPort(tcpPort).udtPort(udtPort).build();
}
}
}