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