/* * Created on 19 Jun 2006 * Created by Paul Gardner * Copyright (C) 2006 Aelitis, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SAS au capital de 46,603.30 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package org.gudy.azureus2.pluginsimpl.local.messaging; import java.nio.ByteBuffer; import org.gudy.azureus2.core3.util.DirectByteBuffer; import org.gudy.azureus2.plugins.messaging.MessageException; import org.gudy.azureus2.plugins.messaging.MessageManager; import org.gudy.azureus2.plugins.messaging.generic.GenericMessageEndpoint; import org.gudy.azureus2.plugins.utils.PooledByteBuffer; import org.gudy.azureus2.pluginsimpl.local.utils.PooledByteBufferImpl; import com.aelitis.azureus.core.networkmanager.IncomingMessageQueue; import com.aelitis.azureus.core.networkmanager.NetworkConnection; import com.aelitis.azureus.core.networkmanager.NetworkManager; import com.aelitis.azureus.core.networkmanager.OutgoingMessageQueue; import com.aelitis.azureus.core.peermanager.messaging.Message; public class GenericMessageConnectionDirect implements GenericMessageConnectionAdapter { public static final int MAX_MESSAGE_SIZE = GenericMessageDecoder.MAX_MESSAGE_LENGTH; protected static GenericMessageConnectionDirect receive( GenericMessageEndpointImpl endpoint, String msg_id, String msg_desc, int stream_crypto, byte[][] shared_secrets ) { GenericMessageConnectionDirect direct_connection = new GenericMessageConnectionDirect( msg_id, msg_desc, endpoint, stream_crypto, shared_secrets ); return( direct_connection ); } private GenericMessageConnectionImpl owner; private String msg_id; private String msg_desc; private int stream_crypto; private byte[][] shared_secrets; private GenericMessageEndpointImpl endpoint; private NetworkConnection connection; private volatile boolean connected; private volatile boolean closed; protected GenericMessageConnectionDirect( String _msg_id, String _msg_desc, GenericMessageEndpointImpl _endpoint, int _stream_crypto, byte[][] _shared_secrets ) { msg_id = _msg_id; msg_desc = _msg_desc; endpoint = _endpoint; stream_crypto = _stream_crypto; shared_secrets = _shared_secrets; } public void setOwner( GenericMessageConnectionImpl _owner ) { owner = _owner; } public int getMaximumMessageSize() { return( MAX_MESSAGE_SIZE ); } /** * Incoming connect call * @param _connection */ protected void connect( NetworkConnection _connection ) { connection = _connection; connection.connect( false, new NetworkConnection.ConnectionListener() { public void connectStarted() { } public void connectSuccess( ByteBuffer remaining_initial_data ) { connected = true; } public void connectFailure( Throwable failure_msg ) { owner.reportFailed( failure_msg ); connection.close(); } public void exceptionThrown( Throwable error ) { owner.reportFailed( error ); connection.close(); } public String getDescription() { return( "generic connection: " + connection.getString()); } }); } public void accepted() { startProcessing(); } public GenericMessageEndpoint getEndpoint() { return( endpoint ); } public void connect( ByteBuffer upper_initial_data, final GenericMessageConnectionAdapter.ConnectionListener listener ) { if ( connected ){ return; } connection = NetworkManager.getSingleton().createConnection( endpoint.getConnectionEndpoint(), new GenericMessageEncoder(), new GenericMessageDecoder( msg_id, msg_desc ), stream_crypto != MessageManager.STREAM_ENCRYPTION_NONE, // use crypto stream_crypto != MessageManager.STREAM_ENCRYPTION_RC4_REQUIRED, // allow fallback shared_secrets ); ByteBuffer initial_data = ByteBuffer.wrap( msg_id.getBytes()); if ( upper_initial_data != null ){ GenericMessage gm = new GenericMessage( msg_id, msg_desc, new DirectByteBuffer( upper_initial_data ), false ); DirectByteBuffer[] payload = new GenericMessageEncoder().encodeMessage( gm )[0].getRawData(); int size = initial_data.remaining(); for (int i=0;i<payload.length;i++){ size += payload[i].remaining( DirectByteBuffer.SS_MSG ); } ByteBuffer temp = ByteBuffer.allocate( size ); temp.put( initial_data ); for (int i=0;i<payload.length;i++){ temp.put( payload[i].getBuffer( DirectByteBuffer.SS_MSG )); } temp.rewind(); initial_data = temp; } connection.connect( initial_data, false, new NetworkConnection.ConnectionListener() { public void connectStarted() { } public void connectSuccess( ByteBuffer remaining_initial_data ) { connected = true; try{ if ( remaining_initial_data != null && remaining_initial_data.remaining() > 0){ // queue as a *raw* message as already encoded connection.getOutgoingMessageQueue().addMessage( new GenericMessage( msg_id, msg_desc, new DirectByteBuffer( remaining_initial_data ), true), false ); } listener.connectSuccess(); startProcessing(); }catch( Throwable e ){ connectFailure( e ); } } public void connectFailure( Throwable failure_msg ) { listener.connectFailure( failure_msg ); connection.close(); } public void exceptionThrown( Throwable error ) { listener.connectFailure( error ); connection.close(); } public String getDescription() { return( "generic connection: " + connection.getString()); } }); } protected void startProcessing() { connection.getIncomingMessageQueue().registerQueueListener( new IncomingMessageQueue.MessageQueueListener() { public boolean messageReceived( Message _message ) { GenericMessage message = (GenericMessage)_message; owner.receive( message ); return( true ); } public void protocolBytesReceived( int byte_count ) { } public void dataBytesReceived( int byte_count ) { } }); connection.getOutgoingMessageQueue().registerQueueListener( new OutgoingMessageQueue.MessageQueueListener() { public boolean messageAdded( Message message ) { //System.out.println( " added: " + message ); return( true ); } public void messageQueued( Message message ) { //System.out.println( " queued: " + message ); } public void messageRemoved( Message message ) { //System.out.println( " removed: " + message ); } public void messageSent( Message message ) { //System.out.println( " sent: " + message ); } public void protocolBytesSent( int byte_count ) { } public void dataBytesSent( int byte_count ) { } public void flush(){} }); } public void send( PooledByteBuffer data ) throws MessageException { if ( !connected ){ throw( new MessageException( "not connected" )); } PooledByteBufferImpl impl = (PooledByteBufferImpl)data; try{ connection.getOutgoingMessageQueue().addMessage( new GenericMessage( msg_id, msg_desc, impl.getBuffer(), false ), false ); }catch( Throwable e ){ throw( new MessageException( "send failed", e )); } } public void close() throws MessageException { if ( !connected ){ throw( new MessageException( "not connected" )); } if ( !closed ){ closed = true; connection.close(); } } }