package org.limewire.net.address;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Inet4Address;
import java.nio.ByteOrder;
import java.util.Set;
import org.limewire.inject.EagerSingleton;
import org.limewire.io.Address;
import org.limewire.io.BadGGEPBlockException;
import org.limewire.io.BadGGEPPropertyException;
import org.limewire.io.Connectable;
import org.limewire.io.ConnectableImpl;
import org.limewire.io.GGEP;
import org.limewire.io.IOUtils;
import org.limewire.io.InvalidDataException;
import org.limewire.io.IpPort;
import org.limewire.io.NetworkUtils;
import com.google.inject.Inject;
@EagerSingleton
public class ConnectableSerializer implements AddressSerializer {
private static final int IP_V4 = 0;
private static final int IP_V6 = 1;
static final String CONNECTABLE = "CN";
public String getAddressType() {
return "direct-connect";
}
@Override
public boolean canSerialize(Address address) {
return address instanceof Connectable;
}
public Address deserialize(String address) throws IOException {
if(address.indexOf(':') == -1) {
address += ":6346";
}
return NetworkUtils.parseIpPort(address, false);
}
public Connectable deserialize(byte[] serializedAddress) throws IOException {
try {
GGEP ggep = new GGEP(serializedAddress);
InputStream in = new ByteArrayInputStream(ggep.getBytes(CONNECTABLE));
int hostPortLength = (IOUtils.readByte(in) == IP_V4 ? 4 : 16) + 2;
byte[] hostPort = new byte[hostPortLength];
IOUtils.readFully(in, hostPort);
try {
IpPort ipPort = NetworkUtils.getIpPort(hostPort, ByteOrder.BIG_ENDIAN);
boolean supportsTLS = IOUtils.readByte(in) == (byte)1;
return new ConnectableImpl(ipPort, supportsTLS);
} catch (InvalidDataException e) {
throw new IOException(e);
}
} catch (BadGGEPBlockException e) {
throw new IOException(e);
} catch (BadGGEPPropertyException e) {
throw new IOException(e);
}
}
public Set<Connectable> deserializeSet(byte[] serializedSet) throws IOException {
try {
GGEP ggep = new GGEP(serializedSet);
StrictIpPortSet<Connectable> set = new StrictIpPortSet<Connectable>();
for (int i = 0; ggep.hasValueFor(CONNECTABLE + i); i++) {
set.add(deserialize(ggep.getBytes(CONNECTABLE + i)));
}
return set;
} catch (BadGGEPBlockException e) {
throw new IOException(e);
} catch (BadGGEPPropertyException e) {
throw new IOException(e);
}
}
public byte[] serialize(Address address) throws IOException {
Connectable connectable = (Connectable)address;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int type = connectable.getInetAddress() instanceof Inet4Address ? IP_V4 : IP_V6;
bos.write(type);
bos.write(NetworkUtils.getBytes(connectable, ByteOrder.BIG_ENDIAN));
bos.write(connectable.isTLSCapable() ? (byte)1 : (byte) 0);
GGEP ggep = new GGEP();
ggep.put(CONNECTABLE, bos.toByteArray());
return ggep.toByteArray();
}
public byte[] serialize(Set<Connectable> addresses) throws IOException {
GGEP ggep = new GGEP();
int i = 0;
for (Connectable connectable : addresses) {
ggep.put(CONNECTABLE + i, serialize(connectable));
++i;
}
return ggep.toByteArray();
}
@Inject
public void register(AddressFactory factory) {
factory.registerSerializer(this);
}
}