package com.limegroup.gnutella.messagehandlers;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import org.limewire.io.NetworkUtils;
import org.limewire.security.AbstractSecurityToken;
import org.limewire.security.InvalidSecurityTokenException;
import org.limewire.security.MACCalculatorRepositoryManager;
import org.limewire.security.SecurityToken;
import org.limewire.service.ErrorService;
import com.limegroup.gnutella.ReplyHandler;
/**
* A security token to be used in the OOB v3 protocol.
*/
public class OOBSecurityToken extends AbstractSecurityToken {
/**
* Creates a security token with the provided data.
* The query key consists of the # of results followed
* by the MAC checksum of the data object.
*/
public OOBSecurityToken(OOBTokenData data, MACCalculatorRepositoryManager manager) {
super(data, manager);
}
/**
* Creates a key from data received from the network. The first
* byte is the # of results, the rest are the checksum to verify against.
* @throws InvalidSecurityTokenException
*/
public OOBSecurityToken(byte[] network, MACCalculatorRepositoryManager manager) throws InvalidSecurityTokenException {
super(network, manager);
}
@Override
protected byte [] getFromMAC(byte[] b, TokenData data) {
byte [] ret = new byte[b.length+1];
ret[0] = (byte)((OOBTokenData)data).getNumRequests();
System.arraycopy(b, 0, ret, 1, b.length);
return ret;
}
/** Returns true if the data is an OOBTokenData. */
@Override
protected boolean isValidTokenData(TokenData data) {
return data instanceof OOBTokenData;
}
public static class OOBTokenData implements SecurityToken.TokenData {
private final int numRequests;
private final byte [] data;
public OOBTokenData(ReplyHandler replyHandler, byte [] guid, int numRequests) {
this(replyHandler.getInetAddress(), replyHandler.getPort(), guid, numRequests);
}
public OOBTokenData(InetAddress address, int port, byte[] guid, int numRequests) {
if (numRequests < 0 || numRequests > 255) {
throw new IllegalArgumentException("requestNum to small or too large " + numRequests);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(35);
DataOutputStream data = new DataOutputStream(baos);
try {
data.writeShort(port);
if (NetworkUtils.isIPv6Compatible(address)) {
data.write(NetworkUtils.getIPv6AddressBytes(address));
}
else {
// unknown inet address, write its full address bytes
data.write(address.getAddress());
}
data.write(numRequests);
data.write(guid);
}
catch (IOException ie) {
ErrorService.error(ie);
}
this.data = baos.toByteArray();
this.numRequests = numRequests;
}
public byte [] getData() {
return data;
}
public int getNumRequests() {
return numRequests;
}
}
}