package com.aelitis.azureus.core.peermanager.messaging.bittorrent.ltep;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.gudy.azureus2.core3.util.*;
import com.aelitis.azureus.core.peermanager.messaging.Message;
import com.aelitis.azureus.core.peermanager.messaging.MessageException;
import com.aelitis.azureus.core.peermanager.messaging.MessagingUtil;
public class LTHandshake implements LTMessage {
private Map data_dict;
private byte[] bencoded_data;
private String bencoded_string;
private String description;
private byte version;
private DirectByteBuffer[] buffer_array;
public LTHandshake(Map data_dict, byte version) {
this.data_dict = (data_dict == null) ? Collections.EMPTY_MAP : data_dict;
this.version = version;
}
public Message deserialize(DirectByteBuffer data, byte version) throws MessageException {
if (data == null) {
throw new MessageException( "[" +getID() + "] decode error: data == null");
}
if (data.remaining(DirectByteBuffer.SS_MSG ) < 1) {
throw new MessageException( "[" +getID() + "] decode error: less than 1 byte in payload");
}
// Try decoding the data now.
Map res_data_dict = MessagingUtil.convertBencodedByteStreamToPayload(data, 1, getID());
LTHandshake result = new LTHandshake(res_data_dict, this.version);
return result;
}
public DirectByteBuffer[] getData() {
if (buffer_array == null) {
buffer_array = new DirectByteBuffer[1];
DirectByteBuffer buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_LT_HANDSHAKE, getBencodedData().length);
buffer_array[0] = buffer;
buffer.put(DirectByteBuffer.SS_MSG, getBencodedData());
buffer.flip(DirectByteBuffer.SS_MSG);
}
return buffer_array;
}
public void destroy() {
this.data_dict = null;
this.bencoded_data = null;
this.description = null;
if (buffer_array != null) {
buffer_array[0].returnToPool();
}
this.buffer_array = null;
}
public String getDescription() {
if (description == null) {
description = LTMessage.ID_LT_HANDSHAKE.toUpperCase() + ": " + this.getBencodedString();
}
return description;
}
public String getBencodedString() {
if (this.bencoded_string == null) {
try {
this.bencoded_string = new String(this.getBencodedData(), Constants.BYTE_ENCODING);
}
catch (java.io.UnsupportedEncodingException uee) {
this.bencoded_string = "";
Debug.printStackTrace(uee);
}
}
return this.bencoded_string;
}
public byte[] getBencodedData() {
if (this.bencoded_data == null) {
try {this.bencoded_data = BEncoder.encode(this.data_dict);}
catch (java.io.IOException ioe) {
this.bencoded_data = new byte[0];
Debug.printStackTrace(ioe);
}
}
return this.bencoded_data;
}
public Map getDataMap() {
return this.data_dict;
}
public String getClientName() {
byte[] client_name = (byte[])data_dict.get("v");
if (client_name == null) {return null;}
try {return new String(client_name, Constants.DEFAULT_ENCODING);}
catch (java.io.IOException ioe) {return null;}
}
public boolean isUploadOnly() {
// been seeing a bunch of
// java.lang.ClassCastException: [B cannot be cast to java.lang.Long
// at com.aelitis.azureus.core.peermanager.messaging.bittorrent.ltep.LTHandshake.isUploadOnly(LTHandshake.java:108)
Object ulOnly = data_dict.get("upload_only");
/* NO, this is totally wrong - the entry in the extensions dict indicates the support of an 'upload_only' extension message
* http://forum.utorrent.com/viewtopic.php?id=53911
*
if ( ulOnly == null ){
// apparently it is actually supposed to be in the extensions dict...
Map ext_dict = (Map)data_dict.get("m");
if ( ext_dict != null ){
ulOnly = ext_dict.get("upload_only");
}
}
*/
if ( ulOnly == null ){
return( false );
}else if ( ulOnly instanceof Number ){
Number n_ulOnly = (Number)ulOnly;
return n_ulOnly.longValue() > 0L;
}else{
// seeing String value '0' here....
if ( ulOnly instanceof byte[] ){
String str_val = new String((byte[])ulOnly );
try{
int i = Integer.parseInt( str_val );
return( i > 0 );
}catch( Throwable e ){
}
}
String debug;
if ( ulOnly instanceof byte[] ){
byte[] bytes = (byte[])ulOnly;
debug = new String(bytes) + "/";
for ( int i=0;i<bytes.length;i++){
debug += (i==0?"":",") + (((int)bytes[i]) & 0x00ff );
}
}else{
debug = String.valueOf( ulOnly );
}
Debug.out( "Invalid entry for 'upload_only' - " + debug + ", map=" + data_dict );
return( false );
}
}
public InetAddress getIPv6() {
byte[] addr = (byte[])data_dict.get("ipv6");
if(addr != null && addr.length == 16)
{
try
{
return InetAddress.getByAddress(addr);
} catch (UnknownHostException e)
{
// should not happen
e.printStackTrace();
}
}
return null;
}
public int getTCPListeningPort()
{
Long port = (Long)data_dict.get("p");
if(port == null)
return 0;
int val = port.intValue();
if(val <= 65535 && val > 0)
return val;
return 0;
}
public Boolean isCryptoRequested()
{
Long crypto = (Long)data_dict.get("e");
if(crypto == null)
return null;
return Boolean.valueOf(crypto.longValue() == 1);
}
public Map getExtensionMapping() {
Map result = (Map)data_dict.get("m");
return (result == null) ? Collections.EMPTY_MAP : result;
}
public int
getMetadataSize()
{
Long l = (Long)data_dict.get( "metadata_size" );
if ( l != null ){
return( l.intValue());
}
return( 0 );
}
public void
addDefaultExtensionMappings(
boolean enable_pex,
boolean enable_md,
boolean enable_uo )
{
if ( enable_pex || enable_md || enable_uo ){
Map ext = (Map)data_dict.get("m");
if ( ext == null ){
ext = new HashMap();
data_dict.put( "m", ext );
}
if ( enable_pex ){
ext.put( ID_UT_PEX, new Long( SUBID_UT_PEX ));
}
if ( enable_md ){
ext.put( ID_UT_METADATA, new Long( SUBID_UT_METADATA ));
}
if ( enable_uo ){
ext.put( ID_UT_UPLOAD_ONLY, new Long( SUBID_UT_UPLOAD_ONLY ));
}
}
}
public String getFeatureID() {return LTMessage.LT_FEATURE_ID;}
public int getFeatureSubID() {return LTMessage.SUBID_LT_HANDSHAKE;}
public String getID() {return LTHandshake.ID_LT_HANDSHAKE;}
public byte[] getIDBytes() {return LTHandshake.ID_LT_HANDSHAKE_BYTES;}
public int getType() {return Message.TYPE_PROTOCOL_PAYLOAD;}
public byte getVersion() {return this.version;}
}