AZMessageFactorypublic class AZMessageFactory extends Object Factory for handling AZ message creation.
NOTE: wire format: [total message length] + [id length] + [id bytes] + [version byte] + [payload bytes] |
Fields Summary |
---|
public static final byte | MESSAGE_VERSION_INITIAL | public static final byte | MESSAGE_VERSION_SUPPORTS_PADDING | public static final int | AZ_HANDSHAKE_PAD_MAX | public static final int | SMALL_PAD_MAX | public static final int | BIG_PAD_MAX | private static final byte | bss | private static final Map | legacy_data |
Methods Summary |
---|
public static Message | createAZMessage(DirectByteBuffer stream_payload)Construct a new AZ message instance from the given message raw byte stream.
int id_length = stream_payload.getInt( bss );
if( id_length < 1 || id_length > 1024 || id_length > stream_payload.remaining( bss ) - 1 ) {
byte bt_id = stream_payload.get( (byte)0, 0 );
throw new MessageException( "invalid AZ id length given: " +id_length+ ", stream_payload.remaining(): " +stream_payload.remaining( bss )+ ", BT id?=" +bt_id );
}
byte[] id_bytes = new byte[ id_length ];
stream_payload.get( bss, id_bytes );
// if only the version came first we could save a lot of space by changing the id length + id....
// in the meantime we overload the version byte to have a version number and flags
// flags = top 4 bits, version = bottom 4 bits
byte version_and_flags = stream_payload.get( bss );
byte version = (byte)( version_and_flags & 0x0f );
if ( version >= MESSAGE_VERSION_SUPPORTS_PADDING ){
byte flags = (byte)(( version_and_flags >> 4 ) & 0x0f );
if ( ( flags & 0x01 ) != 0 ){
short padding_length = stream_payload.getShort( bss );
byte[] padding = new byte[padding_length];
stream_payload.get( bss, padding );
}
}
return MessageManager.getSingleton().createMessage( id_bytes, stream_payload, version );
| public static com.aelitis.azureus.core.networkmanager.RawMessage | createAZRawMessage(Message base_message, boolean enable_padding)Create the proper AZ raw message from the given base message.
byte[] id_bytes = base_message.getIDBytes();
byte version = base_message.getVersion();
DirectByteBuffer[] payload = base_message.getData();
int payload_size = 0;
for( int i=0; i < payload.length; i++ ) {
payload_size += payload[i].remaining( bss );
}
//create and fill header buffer
DirectByteBuffer header;
if ( version >= MESSAGE_VERSION_SUPPORTS_PADDING ){
short padding_length = enable_padding?(short)(( Math.random() * ( payload_size>256?SMALL_PAD_MAX:BIG_PAD_MAX ))+1):0;
byte flags = enable_padding?(byte)0x01:(byte)0x00;
int header_size = 4 + 4 + id_bytes.length + 1 + (enable_padding?(2+padding_length):0);
header = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_MSG_AZ_HEADER, header_size );
header.putInt( bss, header_size - 4 + payload_size );
header.putInt( bss, id_bytes.length );
header.put( bss, id_bytes );
byte version_and_flags = (byte)( ( flags << 4 ) | version );
header.put( bss, version_and_flags );
if ( enable_padding ){
byte[] padding = new byte[padding_length];
header.putShort( bss, padding_length );
header.put( bss, padding );
}
}else{
int header_size = 4 + 4 + id_bytes.length + 1;
header = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_MSG_AZ_HEADER, header_size );
header.putInt( bss, header_size - 4 + payload_size );
header.putInt( bss, id_bytes.length );
header.put( bss, id_bytes );
header.put( bss, version );
}
header.flip( bss );
DirectByteBuffer[] raw_buffs = new DirectByteBuffer[ payload.length + 1 ];
raw_buffs[0] = header;
for( int i=0; i < payload.length; i++ ) {
raw_buffs[i+1] = payload[i];
}
String message_id = base_message.getID();
LegacyData ld = (LegacyData)legacy_data.get( message_id ); //determine if a legacy BT message
if( ld != null ) { //legacy message, use pre-configured values
return new RawMessageImpl( base_message, raw_buffs, ld.priority, ld.is_no_delay, ld.to_remove );
}
// these should really be properties of the message...
int priority;
boolean no_delay = true;
if ( message_id == AZMessage.ID_AZ_HANDSHAKE ){
// handshake needs to go out first - if not high then bitfield can get in front of it...
priority = RawMessage.PRIORITY_HIGH;
}else if ( message_id == AZMessage.ID_AZ_HAVE ){
priority = RawMessage.PRIORITY_LOW;
no_delay = false;
}else{
//standard message, ensure that protocol messages have wire priority over data payload messages
priority = base_message.getType() == Message.TYPE_DATA_PAYLOAD ? RawMessage.PRIORITY_LOW : RawMessage.PRIORITY_NORMAL;
}
return new RawMessageImpl( base_message, raw_buffs, priority, no_delay, null );
| public static void | init()Initialize the factory, i.e. register the messages with the message manager.
legacy_data.put( BTMessage.ID_BT_CHOKE, new LegacyData( RawMessage.PRIORITY_HIGH, true, new Message[]{new BTUnchoke((byte)0), new BTPiece(-1, -1, null,(byte)0 )} ) );
legacy_data.put( BTMessage.ID_BT_UNCHOKE, new LegacyData( RawMessage.PRIORITY_NORMAL, true, new Message[]{new BTChoke((byte)0)} ) );
legacy_data.put( BTMessage.ID_BT_INTERESTED, new LegacyData( RawMessage.PRIORITY_HIGH, true, new Message[]{new BTUninterested((byte)0)} ) );
legacy_data.put( BTMessage.ID_BT_UNINTERESTED, new LegacyData( RawMessage.PRIORITY_NORMAL, false, new Message[]{new BTInterested((byte)0)} ) );
legacy_data.put( BTMessage.ID_BT_HAVE, new LegacyData( RawMessage.PRIORITY_LOW, false, null ) );
legacy_data.put( BTMessage.ID_BT_BITFIELD, new LegacyData( RawMessage.PRIORITY_HIGH, true, null ) );
legacy_data.put( BTMessage.ID_BT_REQUEST, new LegacyData( RawMessage.PRIORITY_NORMAL, true, null ) );
legacy_data.put( BTMessage.ID_BT_PIECE, new LegacyData( RawMessage.PRIORITY_LOW, false, null ) );
legacy_data.put( BTMessage.ID_BT_CANCEL, new LegacyData( RawMessage.PRIORITY_HIGH, true, null ) );
legacy_data.put( BTMessage.ID_BT_HANDSHAKE, new LegacyData( RawMessage.PRIORITY_HIGH, true, null ) );
legacy_data.put( BTMessage.ID_BT_KEEP_ALIVE, new LegacyData( RawMessage.PRIORITY_LOW, false, null ) );
legacy_data.put( BTMessage.ID_BT_LT_EXTENSION_HANDSHAKE, new LegacyData (RawMessage.PRIORITY_HIGH, false, null));
try {
MessageManager.getSingleton().registerMessageType( new AZHandshake( new byte[20], "", "", 0, 0, 0, new String[0], new byte[0], 0, MESSAGE_VERSION_SUPPORTS_PADDING ) );
MessageManager.getSingleton().registerMessageType( new AZPeerExchange( new byte[20], null, null, MESSAGE_VERSION_SUPPORTS_PADDING ));
MessageManager.getSingleton().registerMessageType( new AZRequestHint( -1, -1, -1, -1, MESSAGE_VERSION_SUPPORTS_PADDING ));
MessageManager.getSingleton().registerMessageType( new AZHave( new int[0], MESSAGE_VERSION_SUPPORTS_PADDING ));
MessageManager.getSingleton().registerMessageType( new AZBadPiece( -1, MESSAGE_VERSION_SUPPORTS_PADDING ));
/*
MessageManager.getSingleton().registerMessageType( new AZSessionSyn( new byte[20], -1, null) );
MessageManager.getSingleton().registerMessageType( new AZSessionAck( new byte[20], -1, null) );
MessageManager.getSingleton().registerMessageType( new AZSessionEnd( new byte[20], "" ) );
MessageManager.getSingleton().registerMessageType( new AZSessionBitfield( -1, null ) );
MessageManager.getSingleton().registerMessageType( new AZSessionCancel( -1, -1, -1, -1 ) );
MessageManager.getSingleton().registerMessageType( new AZSessionHave( -1, new int[]{-1} ) );
MessageManager.getSingleton().registerMessageType( new AZSessionPiece( -1, -1, -1, null ) );
MessageManager.getSingleton().registerMessageType( new AZSessionRequest( -1, (byte)-1, -1, -1, -1 ) );
*/
}
catch( MessageException me ) { me.printStackTrace(); }
| public static void | registerGenericMapPayloadMessageType(java.lang.String type_id)Register a generic map payload type with the factory.
MessageManager.getSingleton().registerMessageType( new AZGenericMapPayload( type_id, null, MESSAGE_VERSION_INITIAL ) );
|
|