1 /* 2 * Created on Feb 9, 2005 3 * Created by Alon Rohter 4 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 */ 19 20 package com.aelitis.azureus.core.peermanager.messaging.bittorrent; 21 22 import java.util.HashMap; 23 24 import org.gudy.azureus2.core3.logging.*; 25 import org.gudy.azureus2.core3.util.Debug; 26 import org.gudy.azureus2.core3.util.DirectByteBuffer; 27 import org.gudy.azureus2.core3.util.DirectByteBufferPool; 28 29 import com.aelitis.azureus.core.networkmanager.RawMessage; 30 import com.aelitis.azureus.core.networkmanager.impl.RawMessageImpl; 31 import com.aelitis.azureus.core.peermanager.messaging.*; 32 33 34 /** 35 * 36 */ 37 public class BTMessageFactory { 38 public static final byte MESSAGE_VERSION_INITIAL = 1; 39 public static final byte MESSAGE_VERSION_SUPPORTS_PADDING = 2; // most of these messages are also used by AZ code 40 41 private static final LogIDs LOGID = LogIDs.PEER; 42 43 /** 44 * Initialize the factory, i.e. register the messages with the message manager. 45 */ init()46 public static void init() { 47 try { 48 MessageManager.getSingleton().registerMessageType( new BTBitfield( null, MESSAGE_VERSION_SUPPORTS_PADDING )); 49 MessageManager.getSingleton().registerMessageType( new BTCancel( -1, -1, -1, MESSAGE_VERSION_SUPPORTS_PADDING )); 50 MessageManager.getSingleton().registerMessageType( new BTChoke( MESSAGE_VERSION_SUPPORTS_PADDING )); 51 MessageManager.getSingleton().registerMessageType( new BTHandshake( new byte[0], new byte[0], BTHandshake.AZ_RESERVED_MODE, MESSAGE_VERSION_INITIAL )); 52 MessageManager.getSingleton().registerMessageType( new BTHave( -1, MESSAGE_VERSION_SUPPORTS_PADDING )); 53 MessageManager.getSingleton().registerMessageType( new BTInterested( MESSAGE_VERSION_SUPPORTS_PADDING )); 54 MessageManager.getSingleton().registerMessageType( new BTKeepAlive(MESSAGE_VERSION_SUPPORTS_PADDING )); 55 MessageManager.getSingleton().registerMessageType( new BTPiece( -1, -1, null, MESSAGE_VERSION_SUPPORTS_PADDING )); 56 MessageManager.getSingleton().registerMessageType( new BTRequest( -1, -1 , -1, MESSAGE_VERSION_SUPPORTS_PADDING )); 57 MessageManager.getSingleton().registerMessageType( new BTUnchoke( MESSAGE_VERSION_SUPPORTS_PADDING )); 58 MessageManager.getSingleton().registerMessageType( new BTUninterested( MESSAGE_VERSION_SUPPORTS_PADDING )); 59 MessageManager.getSingleton().registerMessageType( new BTSuggestPiece( -1, MESSAGE_VERSION_SUPPORTS_PADDING )); 60 MessageManager.getSingleton().registerMessageType( new BTHaveAll( MESSAGE_VERSION_SUPPORTS_PADDING )); 61 MessageManager.getSingleton().registerMessageType( new BTHaveNone( MESSAGE_VERSION_SUPPORTS_PADDING )); 62 MessageManager.getSingleton().registerMessageType( new BTRejectRequest( -1, -1, -1, MESSAGE_VERSION_SUPPORTS_PADDING )); 63 MessageManager.getSingleton().registerMessageType( new BTAllowedFast( -1, MESSAGE_VERSION_SUPPORTS_PADDING )); 64 MessageManager.getSingleton().registerMessageType( new BTLTMessage( null, MESSAGE_VERSION_SUPPORTS_PADDING )); 65 MessageManager.getSingleton().registerMessageType( new BTDHTPort(-1)); 66 } 67 catch( MessageException me ) { me.printStackTrace(); } 68 } 69 70 71 72 73 private static final String[] id_to_name = new String[21]; 74 private static final HashMap legacy_data = new HashMap(); 75 static { 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 )}, (byte)0 ) )76 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 )}, (byte)0 ) ); 77 id_to_name[0] = BTMessage.ID_BT_CHOKE; 78 legacy_data.put( BTMessage.ID_BT_UNCHOKE, new LegacyData( RawMessage.PRIORITY_NORMAL, true, new Message[]{new BTChoke((byte)0)}, (byte)1 ) )79 legacy_data.put( BTMessage.ID_BT_UNCHOKE, new LegacyData( RawMessage.PRIORITY_NORMAL, true, new Message[]{new BTChoke((byte)0)}, (byte)1 ) ); 80 id_to_name[1] = BTMessage.ID_BT_UNCHOKE; 81 legacy_data.put( BTMessage.ID_BT_INTERESTED, new LegacyData( RawMessage.PRIORITY_HIGH, true, new Message[]{new BTUninterested((byte)0)}, (byte)2 ) )82 legacy_data.put( BTMessage.ID_BT_INTERESTED, new LegacyData( RawMessage.PRIORITY_HIGH, true, new Message[]{new BTUninterested((byte)0)}, (byte)2 ) ); 83 id_to_name[2] = BTMessage.ID_BT_INTERESTED; 84 legacy_data.put( BTMessage.ID_BT_UNINTERESTED, new LegacyData( RawMessage.PRIORITY_NORMAL, false, new Message[]{new BTInterested((byte)0)}, (byte)3 ) )85 legacy_data.put( BTMessage.ID_BT_UNINTERESTED, new LegacyData( RawMessage.PRIORITY_NORMAL, false, new Message[]{new BTInterested((byte)0)}, (byte)3 ) ); 86 id_to_name[3] = BTMessage.ID_BT_UNINTERESTED; 87 legacy_data.put( BTMessage.ID_BT_HAVE, new LegacyData( RawMessage.PRIORITY_LOW, false, null, (byte)4 ) )88 legacy_data.put( BTMessage.ID_BT_HAVE, new LegacyData( RawMessage.PRIORITY_LOW, false, null, (byte)4 ) ); 89 id_to_name[4] = BTMessage.ID_BT_HAVE; 90 legacy_data.put( BTMessage.ID_BT_BITFIELD, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)5 ) )91 legacy_data.put( BTMessage.ID_BT_BITFIELD, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)5 ) ); 92 id_to_name[5] = BTMessage.ID_BT_BITFIELD; 93 legacy_data.put( BTMessage.ID_BT_REQUEST, new LegacyData( RawMessage.PRIORITY_NORMAL, true, null, (byte)6 ) )94 legacy_data.put( BTMessage.ID_BT_REQUEST, new LegacyData( RawMessage.PRIORITY_NORMAL, true, null, (byte)6 ) ); 95 id_to_name[6] = BTMessage.ID_BT_REQUEST; 96 legacy_data.put( BTMessage.ID_BT_PIECE, new LegacyData( RawMessage.PRIORITY_LOW, false, null, (byte)7 ) )97 legacy_data.put( BTMessage.ID_BT_PIECE, new LegacyData( RawMessage.PRIORITY_LOW, false, null, (byte)7 ) ); 98 id_to_name[7] = BTMessage.ID_BT_PIECE; 99 legacy_data.put( BTMessage.ID_BT_CANCEL, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)8 ) )100 legacy_data.put( BTMessage.ID_BT_CANCEL, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)8 ) ); 101 id_to_name[8] = BTMessage.ID_BT_CANCEL; 102 legacy_data.put( BTMessage.ID_BT_DHT_PORT, new LegacyData( RawMessage.PRIORITY_LOW, true, null, (byte)9 ) )103 legacy_data.put( BTMessage.ID_BT_DHT_PORT, new LegacyData( RawMessage.PRIORITY_LOW, true, null, (byte)9 ) ); 104 id_to_name[9] = BTMessage.ID_BT_DHT_PORT; 105 legacy_data.put( BTMessage.ID_BT_SUGGEST_PIECE, new LegacyData( RawMessage.PRIORITY_NORMAL, true, null, (byte)13 ) )106 legacy_data.put( BTMessage.ID_BT_SUGGEST_PIECE, new LegacyData( RawMessage.PRIORITY_NORMAL, true, null, (byte)13 ) ); 107 id_to_name[13] = BTMessage.ID_BT_SUGGEST_PIECE; 108 legacy_data.put( BTMessage.ID_BT_HAVE_ALL, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)14 ) )109 legacy_data.put( BTMessage.ID_BT_HAVE_ALL, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)14 ) ); 110 id_to_name[14] = BTMessage.ID_BT_HAVE_ALL; 111 legacy_data.put( BTMessage.ID_BT_HAVE_NONE, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)15 ) )112 legacy_data.put( BTMessage.ID_BT_HAVE_NONE, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)15 ) ); 113 id_to_name[15] = BTMessage.ID_BT_HAVE_NONE; 114 legacy_data.put( BTMessage.ID_BT_REJECT_REQUEST, new LegacyData( RawMessage.PRIORITY_NORMAL, true, null, (byte)16 ) )115 legacy_data.put( BTMessage.ID_BT_REJECT_REQUEST, new LegacyData( RawMessage.PRIORITY_NORMAL, true, null, (byte)16 ) ); 116 id_to_name[16] = BTMessage.ID_BT_REJECT_REQUEST; 117 legacy_data.put( BTMessage.ID_BT_ALLOWED_FAST, new LegacyData( RawMessage.PRIORITY_LOW, false, null, (byte)17 ) )118 legacy_data.put( BTMessage.ID_BT_ALLOWED_FAST, new LegacyData( RawMessage.PRIORITY_LOW, false, null, (byte)17 ) ); 119 id_to_name[17] = BTMessage.ID_BT_ALLOWED_FAST; 120 legacy_data.put( BTMessage.ID_BT_LT_EXT_MESSAGE, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)20 ) )121 legacy_data.put( BTMessage.ID_BT_LT_EXT_MESSAGE, new LegacyData( RawMessage.PRIORITY_HIGH, true, null, (byte)20 ) ); 122 id_to_name[20] = BTMessage.ID_BT_LT_EXT_MESSAGE; 123 } 124 125 126 127 128 129 130 /** 131 * Construct a new BT message instance from the given message raw byte stream. 132 * @param stream_payload data 133 * @return decoded/deserialized BT message 134 * @throws MessageException if message creation failed 135 * NOTE: Does not auto-return given direct buffer on thrown exception. 136 */ createBTMessage( DirectByteBuffer stream_payload)137 public static Message createBTMessage( DirectByteBuffer stream_payload) throws MessageException { 138 byte id = stream_payload.get( DirectByteBuffer.SS_MSG ); 139 140 switch( id ) { 141 case 0: 142 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_CHOKE_BYTES, stream_payload, (byte)1 ); 143 144 case 1: 145 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_UNCHOKE_BYTES, stream_payload, (byte)1 ); 146 147 case 2: 148 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_INTERESTED_BYTES, stream_payload, (byte)1 ); 149 150 case 3: 151 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_UNINTERESTED_BYTES, stream_payload, (byte)1 ); 152 153 case 4: 154 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_HAVE_BYTES, stream_payload, (byte)1 ); 155 156 case 5: 157 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_BITFIELD_BYTES, stream_payload, (byte)1 ); 158 159 case 6: 160 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_REQUEST_BYTES, stream_payload, (byte)1 ); 161 162 case 7: 163 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_PIECE_BYTES, stream_payload, (byte)1 ); 164 165 case 8: 166 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_CANCEL_BYTES, stream_payload, (byte)1 ); 167 168 case 9: 169 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_DHT_PORT_BYTES, stream_payload, (byte)1 ); 170 171 case 13: 172 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_SUGGEST_PIECE_BYTES, stream_payload, (byte)1 ); 173 174 case 14: 175 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_HAVE_ALL_BYTES, stream_payload, (byte)1 ); 176 177 case 15: 178 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_HAVE_NONE_BYTES, stream_payload, (byte)1 ); 179 180 case 16: 181 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_REJECT_REQUEST_BYTES, stream_payload, (byte)1 ); 182 183 case 17: 184 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_ALLOWED_FAST_BYTES, stream_payload, (byte)1 ); 185 186 case 20: 187 //Clients seeing our handshake reserved bit will send us the old 'extended' messaging hello message accidentally. 188 //Instead of throwing an exception and dropping the peer connection, we'll just fake it as a keep-alive :) 189 if (Logger.isEnabled()) 190 Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, 191 "Old extended messaging hello received (or malformed LT extension message), " 192 + "ignoring and faking as keep-alive.")); 193 return MessageManager.getSingleton().createMessage( BTMessage.ID_BT_KEEP_ALIVE_BYTES, null, (byte)1 ); 194 195 default: { System.out.println( "Unknown BT message id [" +id+ "]" ); 196 throw new MessageException( "Unknown BT message id [" +id+ "]" ); 197 } 198 } 199 } 200 201 202 getMessageType( DirectByteBuffer stream_payload )203 public static int getMessageType( DirectByteBuffer stream_payload ) { 204 byte id = stream_payload.get( DirectByteBuffer.SS_MSG, 0 ); 205 if( id == 84 ) return Message.TYPE_PROTOCOL_PAYLOAD; //handshake message byte in position 4 206 if ( id >= 0 && id < id_to_name.length ){ 207 String name = id_to_name[ id ]; 208 209 if ( name != null ){ 210 211 Message message = MessageManager.getSingleton().lookupMessage( name ); 212 213 if ( message != null ){ 214 215 return( message.getType()); 216 } 217 } 218 } 219 // invalid, return whatever 220 return Message.TYPE_PROTOCOL_PAYLOAD; 221 } 222 223 224 225 /** 226 * Create the proper BT raw message from the given base message. 227 * @param base_message to create from 228 * @return BT raw message 229 */ createBTRawMessage( Message base_message )230 public static RawMessage createBTRawMessage( Message base_message ) { 231 if( base_message instanceof RawMessage ) { //used for handshake and keep-alive messages 232 return (RawMessage)base_message; 233 } 234 235 LegacyData ld = (LegacyData)legacy_data.get( base_message.getID() ); 236 237 if( ld == null ) { 238 Debug.out( "legacy message type id not found for [" +base_message.getID()+ "]" ); 239 return null; //message id type not found 240 } 241 242 DirectByteBuffer[] payload = base_message.getData(); 243 244 int payload_size = 0; 245 for( int i=0; i < payload.length; i++ ) { 246 payload_size += payload[i].remaining( DirectByteBuffer.SS_MSG ); 247 } 248 249 DirectByteBuffer header = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_MSG_BT_HEADER, 5 ); 250 header.putInt( DirectByteBuffer.SS_MSG, 1 + payload_size ); 251 header.put( DirectByteBuffer.SS_MSG, ld.bt_id ); 252 header.flip( DirectByteBuffer.SS_MSG ); 253 254 DirectByteBuffer[] raw_buffs = new DirectByteBuffer[ payload.length + 1 ]; 255 raw_buffs[0] = header; 256 for( int i=0; i < payload.length; i++ ) { 257 raw_buffs[i+1] = payload[i]; 258 } 259 260 return new RawMessageImpl( base_message, raw_buffs, ld.priority, ld.is_no_delay, ld.to_remove ); 261 } 262 263 264 265 266 protected static class LegacyData { 267 protected final int priority; 268 protected final boolean is_no_delay; 269 protected final Message[] to_remove; 270 protected final byte bt_id; 271 LegacyData( int prio, boolean no_delay, Message[] remove, byte btid )272 protected LegacyData( int prio, boolean no_delay, Message[] remove, byte btid ) { 273 this.priority = prio; 274 this.is_no_delay = no_delay; 275 this.to_remove = remove; 276 this.bt_id = btid; 277 } 278 } 279 } 280