FileDocCategorySizeDatePackage
TCPTransportHelper.javaAPI DocAzureus 3.0.3.412163Mon Mar 05 17:13:52 GMT 2007com.aelitis.azureus.core.networkmanager.impl.tcp

TCPTransportHelper

public class TCPTransportHelper extends Object implements com.aelitis.azureus.core.networkmanager.impl.TransportHelper

Fields Summary
public static final int
READ_TIMEOUT
public static final int
CONNECT_TIMEOUT
public static final int
MAX_PARTIAL_WRITE_RETAIN
private static boolean
enable_efficient_io
private final SocketChannel
channel
private ByteBuffer
delayed_write
private Map
user_data
private boolean
trace
Constructors Summary
public TCPTransportHelper(SocketChannel _channel)

	
	     
		channel = _channel;
	
Methods Summary
public voidcancelReadSelects()

		TCPNetworkManager.getSingleton().getReadSelector().cancel( channel );
	
public voidcancelWriteSelects()

		if ( trace ){
			TimeFormatter.milliTrace( "tcp: cancel write selects" );
		}
		
		TCPNetworkManager.getSingleton().getWriteSelector().cancel( channel );
	
public voidclose(java.lang.String reason)

		TCPNetworkManager.getSingleton().getReadSelector().cancel( channel );
		TCPNetworkManager.getSingleton().getWriteSelector().cancel( channel );
		TCPNetworkManager.getSingleton().getConnectDisconnectManager().closeConnection( channel );
	
public booleandelayWrite(java.nio.ByteBuffer buffer)

		if ( delayed_write != null ){
			
			Debug.out( "secondary delayed write" );
			
			return( false );
		}
		
		delayed_write = buffer;
		
		return( true );
	
public voidfailed(java.lang.Throwable reason)

		close( Debug.getNestedExceptionMessage( reason ));
	
public java.net.InetSocketAddressgetAddress()

		return( new InetSocketAddress( channel.socket().getInetAddress(), channel.socket().getPort()));
	
public intgetConnectTimeout()

		return( CONNECT_TIMEOUT );
	
public java.lang.StringgetName()

			// default is TCP so don't clutter up views with this info
		
		return( "" );
	
public intgetReadTimeout()

		return( READ_TIMEOUT );
	
public java.nio.channels.SocketChannelgetSocketChannel()

  return channel; 
public synchronized java.lang.ObjectgetUserData(java.lang.Object key)

		if ( user_data == null ){

			return(null);

		}

		return( user_data.get( key ));
	
public booleanhasDelayedWrite()

		return( delayed_write != null );
	
public booleanminimiseOverheads()

		return( false );
	
public voidpauseReadSelects()

		TCPNetworkManager.getSingleton().getReadSelector().pauseSelects( channel );
	
public voidpauseWriteSelects()

		if ( trace ){
			TimeFormatter.milliTrace( "tcp: pause write selects" );
		}
		
		TCPNetworkManager.getSingleton().getWriteSelector().pauseSelects( channel );
	
public intread(java.nio.ByteBuffer buffer)

  	
		if( channel == null ) {
			
			Debug.out( "channel == null" );
			
			return 0;
		}
		
		int	res = channel.read( buffer );
		
		if ( trace ){
			TimeFormatter.milliTrace( "tcp: read " + res );
		}
		
		return( res );
	
public longread(java.nio.ByteBuffer[] buffers, int array_offset, int length)

  	
		if( channel == null ) {
			Debug.out( "channel == null" );
			return 0;
		}

		if( buffers == null ) {
			Debug.out( "read: buffers == null" );
			return 0;
		}

		long bytes_read = 0;

		if( enable_efficient_io ) {
			try{
				bytes_read = channel.read( buffers, array_offset, length );
			}
			catch( IOException ioe ) {
				//a bug only fixed in Tiger (1.5 series):
				//http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4854354
				String msg = ioe.getMessage();
				if( msg != null && msg.equals( "A non-blocking socket operation could not be completed immediately" ) ) {
					enable_efficient_io = false;
					Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING,
							"WARNING: Multi-buffer socket read failed; switching to single-buffer mode.\n"
							+ "Upgrade to JRE 1.5 (5.0) series to fix this problem!"));
				}

				throw ioe;
			}
		}else{
				//single-buffer mode
			
			for( int i=array_offset; i < (array_offset + length); i++ ) {
				
				int data_length = buffers[ i ].remaining();
				
				int read = channel.read( buffers[ i ] );
				
				bytes_read += read;
				
				if( read < data_length ) {
					
					break;
				}
			}
		}    

		if ( bytes_read < 0 ){
			
			throw new IOException( "end of stream on socket read" );
		}

		if ( trace ){
			TimeFormatter.milliTrace( "tcp: read " + bytes_read );
		}
		
		return bytes_read;
	
public voidregisterForReadSelects(selectListener listener, java.lang.Object attachment)

		TCPNetworkManager.getSingleton().getReadSelector().register(
				channel,
				new VirtualSelectorListener()
				{
					public boolean 
					selectSuccess(
							VirtualChannelSelector	selector, 
							SocketChannel			sc, 
							Object 					attachment )
					{
						return( listener.selectSuccess( TCPTransportHelper.this, attachment ));
					}

					public void 
					selectFailure(
							VirtualChannelSelector	selector, 
							SocketChannel 			sc, 
							Object 					attachment, 
							Throwable 				msg)
					{
						listener.selectFailure( TCPTransportHelper.this, attachment, msg );
					}
				},
				attachment );
	
public voidregisterForWriteSelects(selectListener listener, java.lang.Object attachment)

		TCPNetworkManager.getSingleton().getWriteSelector().register(
				channel,
				new VirtualSelectorListener()
				{
					public boolean 
					selectSuccess(
							VirtualChannelSelector	selector, 
							SocketChannel			sc, 
							Object 					attachment )
					{
						if ( trace ){
							TimeFormatter.milliTrace( "tcp: write select" );
						}

						return( listener.selectSuccess( TCPTransportHelper.this, attachment ));
					}

					public void 
					selectFailure(
							VirtualChannelSelector	selector, 
							SocketChannel 			sc, 
							Object 					attachment, 
							Throwable 				msg)
					{
						listener.selectFailure( TCPTransportHelper.this, attachment, msg );
					}
				},
				attachment );
	
public voidresumeReadSelects()

		TCPNetworkManager.getSingleton().getReadSelector().resumeSelects( channel );
	
public voidresumeWriteSelects()

		if ( trace ){
			TimeFormatter.milliTrace( "tcp: resume write selects" );
		}
		
		TCPNetworkManager.getSingleton().getWriteSelector().resumeSelects( channel );
	
public voidsetTrace(boolean on)

		trace	= on;
	
public synchronized voidsetUserData(java.lang.Object key, java.lang.Object data)

		if ( user_data == null ){

			user_data = new HashMap();
		}

		user_data.put( key, data );
	
public longwrite(java.nio.ByteBuffer[] buffers, int array_offset, int length)

		if( channel == null ){
			
			Debug.out( "channel == null" );
			
			return 0;
		}

		long written_sofar = 0;

		if ( delayed_write != null ){
			
			ByteBuffer[]	buffers2 = new ByteBuffer[length+1];
			
			buffers2[0] = delayed_write;
			
			int	pos = 1;

			for (int i=array_offset;i<array_offset+length;i++){
				
				buffers2[pos++] = buffers[i];
			}
			
			// System.out.println( "delayed write: mult (" + buffers2.length + ")" );

			int	delay_remaining = delayed_write.remaining();

			delayed_write = null;
			
			written_sofar = write( buffers2, 0, buffers2.length );
			
			if ( buffers2[0].hasRemaining()){
				
				delayed_write = buffers2[0];
				
				written_sofar = 0;
				
				// System.out.println( "delayed write: mult incomp" );

			}else{
				
				written_sofar -= delay_remaining;
			}
		}else{
			
			// log( buffers, array_offset, length );
			
			if ( enable_efficient_io ){
				
				try{
					written_sofar = channel.write( buffers, array_offset, length );
					
				}catch( IOException ioe ) {
					
					//a bug only fixed in Tiger (1.5 series):
					//http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4854354
					String msg = ioe.getMessage();
					if( msg != null && msg.equals( "A non-blocking socket operation could not be completed immediately" ) ) {
						enable_efficient_io = false;
						Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING,
								"WARNING: Multi-buffer socket write failed; "
								+ "switching to single-buffer mode.\n"
								+ "Upgrade to JRE 1.5 (5.0) series to fix this problem!"));
					}
					throw ioe;
				}
			}else{
	
					//single-buffer mode
							
				for( int i=array_offset; i < (array_offset + length); i++ ) {
					
					int data_length = buffers[ i ].remaining();
					
					int written = channel.write( buffers[ i ] );
					
					written_sofar += written;
					
					if( written < data_length ) {
						
						break;
					}
				}
			}
		}

	
		if ( trace ){
			TimeFormatter.milliTrace( "tcp: write " + written_sofar );
		}
		
		return written_sofar;
	
public intwrite(java.nio.ByteBuffer buffer, boolean partial_write)

  	
		if ( channel == null ){
			
			Debug.out( "channel == null" );
			
			return 0;
		}
		
			// partial-write means we are guaranteed to get hit with another write straight away
		
		if ( partial_write && delayed_write == null ){
			
			if ( buffer.remaining() < MAX_PARTIAL_WRITE_RETAIN ){
				
				ByteBuffer	copy = ByteBuffer.allocate( buffer.remaining());
				
				copy.put( buffer );
				
				copy.position( 0 );
				
				delayed_write = copy;
				
				return( copy.remaining());
			}
		}
		
		long	written = 0;
		
		if ( delayed_write != null ){
			
			// System.out.println( "delayed write: single" );
			
			ByteBuffer[]	buffers = new ByteBuffer[]{ delayed_write, buffer };
			
			int	delay_remaining = delayed_write.remaining();

			delayed_write = null;
			
			written = write( buffers, 0, 2 );
			
				// note that we can't report delayed bytes actually written as these have already been accounted for and confuse
				// the layers above if we report them now

			if ( buffers[0].hasRemaining()){
				
				delayed_write = buffers[0];
				
				written = 0;
				
				// System.out.println( "delayed write: single incomp" );
			}else{
				
				written -= delay_remaining;
			}
		}else{
			
			// log( buffer );
			
			written = channel.write( buffer );
		}
		
		if ( trace ){
			
			TimeFormatter.milliTrace( "tcp: write " + written );
		}
		
		return((int)written );