package com.limegroup.gnutella.dht.db;
import java.io.IOException;
import java.io.OutputStream;
import org.limewire.io.BadGGEPBlockException;
import org.limewire.io.BadGGEPPropertyException;
import org.limewire.io.GGEP;
import org.limewire.io.NetworkUtils;
import org.limewire.mojito.exceptions.DHTValueException;
import org.limewire.mojito.routing.Version;
import org.limewire.util.ByteUtils;
import com.limegroup.gnutella.security.MerkleTree;
class AltLocValueImpl extends AbstractAltLocValue {
private static final long serialVersionUID = -6975718782217170657L;
private final byte[] guid;
private final int port;
private final long fileSize;
private final byte[] ttroot;
private final boolean firewalled;
private final byte[] data;
private final boolean supportsTLS;
/**
* Constructor for testing purposes
*/
protected AltLocValueImpl(Version version, byte[] guid, int port,
long fileSize, byte[] ttroot, boolean firewalled, boolean supportsTLS) {
super(version);
if (guid == null || guid.length != 16) {
throw new IllegalArgumentException("Illegal GUID");
}
if (!NetworkUtils.isValidPort(port)) {
throw new IllegalArgumentException("Illegal port: " + port);
}
if (version.compareTo(AbstractAltLocValue.VERSION_ONE) >= 0) {
if (fileSize < 0L) {
throw new IllegalArgumentException("Illegal fileSize: " + fileSize);
}
if (ttroot != null && ttroot.length != MerkleTree.HASHSIZE) {
throw new IllegalArgumentException("Illegal ttroot length: " + ttroot.length);
}
}
this.guid = guid;
this.port = port;
this.fileSize = fileSize;
this.ttroot = ttroot;
this.firewalled = firewalled;
this.supportsTLS = supportsTLS;
this.data = AbstractAltLocValue.serialize(this);
}
public AltLocValueImpl(Version version, byte[] data) throws DHTValueException {
super(version);
if (version == null) {
throw new DHTValueException("Version is null");
}
if (data == null) {
throw new DHTValueException("Data is null");
}
this.data = data;
try {
GGEP ggep = new GGEP(data, 0);
this.guid = ggep.getBytes(AbstractAltLocValue.CLIENT_ID);
if (guid.length != 16) {
throw new DHTValueException("Illegal GUID length: " + guid.length);
}
byte[] portBytes = ggep.getBytes(AbstractAltLocValue.PORT);
this.port = ByteUtils.beb2short(portBytes, 0) & 0xFFFF;
if (!NetworkUtils.isValidPort(port)) {
throw new DHTValueException("Illegal port: " + port);
}
byte[] firewalled = ggep.getBytes(AbstractAltLocValue.FIREWALLED);
if (firewalled.length != 1) {
throw new DHTValueException("Illegal Firewalled length: " + firewalled.length);
}
this.firewalled = (firewalled[0] != 0);
this.supportsTLS = ggep.hasKey(AbstractAltLocValue.TLS);
if (version.compareTo(AbstractAltLocValue.VERSION_ONE) >= 0) {
this.fileSize = ggep.getLong(AbstractAltLocValue.LENGTH);
if (ggep.hasKey(AbstractAltLocValue.TTROOT)) {
byte[] ttroot = ggep.getBytes(AbstractAltLocValue.TTROOT);
if (ttroot.length != MerkleTree.HASHSIZE) {
throw new DHTValueException("Illegal ttroot length: " + ttroot.length);
}
this.ttroot = ttroot;
} else {
this.ttroot = null;
}
} else {
this.fileSize = -1L;
this.ttroot = null;
}
} catch (BadGGEPPropertyException err) {
throw new DHTValueException(err);
} catch (BadGGEPBlockException err) {
throw new DHTValueException(err);
}
}
@Override
public int getPort() {
return port;
}
@Override
public byte[] getGUID() {
return guid;
}
@Override
public boolean isFirewalled() {
return firewalled;
}
@Override
public boolean supportsTLS() {
return supportsTLS;
}
@Override
public long getFileSize() {
return fileSize;
}
@Override
public byte[] getRootHash() {
return ttroot;
}
/*
* (non-Javadoc)
* @see org.limewire.mojito.db.DHTValue#getValue()
*/
public byte[] getValue() {
byte[] copy = new byte[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
return copy;
}
/*
* (non-Javadoc)
* @see org.limewire.mojito.db.DHTValue#write(java.io.OutputStream)
*/
public void write(OutputStream out) throws IOException {
out.write(data);
}
}