/* * Created on Aug 28, 2010 * Created by Paul Gardner * * Copyright 2010 Vuze, Inc. 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; version 2 of the License only. * * 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. */ package com.aelitis.azureus.core.networkmanager.impl.utp; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; import org.gudy.azureus2.core3.util.DisplayFormatters; import org.gudy.azureus2.core3.util.SystemTime; public class UTPConnection { private UTPConnectionManager manager; private long utp_socket; private InetSocketAddress remote_address; private long con_id; private UTPTransportHelper transport; private List<ByteBuffer> read_buffers = new LinkedList<ByteBuffer>(); private volatile boolean connected = true; private boolean is_incoming; private volatile boolean is_writable; private volatile boolean is_unusable; private long total_received; private long total_sent; private int last_read_buff = -1; private int last_read = -1; private int last_write_buff = -1; private int last_write = -1; private long close_time; protected UTPConnection( UTPConnectionManager _manager, InetSocketAddress _remote_address, UTPTransportHelper _transport, // null for incoming long _utp_socket, long _con_id ) { manager = _manager; remote_address = _remote_address; transport = _transport; utp_socket = _utp_socket; con_id = _con_id; if ( transport == null ){ is_writable = true; is_incoming = true; } } protected InetSocketAddress getRemoteAddress() { return( remote_address ); } protected long getSocket() { return( utp_socket ); } protected long getConnectionID() { return( con_id ); } protected UTPSelector getSelector() { return( manager.getSelector()); } public boolean isIncoming() { return( is_incoming ); } protected void setTransport( UTPTransportHelper _transport ) { transport = _transport; } protected UTPTransportHelper getTransport() { return( transport ); } protected void setConnected() { if ( transport != null ){ transport.setConnected(); } } protected void receive( ByteBuffer data ) throws IOException { // packets reach us using 8K space regardless of content - trim this back for small protocol // messages to save memory int rem = data.remaining(); total_received += rem; if ( rem < 256 ){ byte[] temp = new byte[rem]; data.get( temp ); data = ByteBuffer.wrap( temp ); } if ( !connected ){ throw( new IOException( "Transport closed" )); } boolean was_empty = false; synchronized( read_buffers ){ was_empty = read_buffers.size() == 0; read_buffers.add( data ); } if ( was_empty ){ transport.canRead(); } } protected int getReceivePendingSize() { synchronized( read_buffers ){ int res = 0; for ( ByteBuffer b: read_buffers ){ res += b.remaining(); } return( res ); } } protected boolean canRead() { synchronized( read_buffers ){ return( read_buffers.size() > 0 ); } } protected void setCanWrite( boolean b ) { if ( is_writable != b ){ is_writable = b; if ( is_writable ){ transport.canWrite(); } } } protected boolean canWrite() { return( is_writable ); } protected int write( ByteBuffer[] buffers, int offset, int length ) throws IOException { int max = 0; for ( int i=offset;i<offset+length;i++){ max += buffers[i].remaining(); } last_write_buff = max; if ( !is_writable ){ last_write = 0; return( 0 ); } int written = manager.write( this, buffers, offset, length ); total_sent += written; last_write = written; // System.out.println( "Connection(" + getID() + ") - write -> " + written ); return( written ); } protected int read( ByteBuffer buffer ) throws IOException { int total = 0; boolean drained = false; last_read_buff = buffer.remaining(); synchronized( read_buffers ){ while( read_buffers.size() > 0 ){ int rem = buffer.remaining(); if ( rem == 0 ){ break; } ByteBuffer b = (ByteBuffer)read_buffers.get(0); int old_limit = b.limit(); if ( b.remaining() > rem ){ b.limit( b.position() + rem ); } buffer.put( b ); b.limit( old_limit ); total += rem - buffer.remaining(); if ( b.hasRemaining()){ break; }else{ read_buffers.remove(0); } } drained = read_buffers.size() == 0; } if ( drained ){ manager.readBufferDrained( this ); } last_read = total; // System.out.println( "Connection(" + getID() + ") - read -> " +total ); return( total ); } protected void close( String reason ) { if ( transport != null ){ transport.close( reason ); }else{ closeSupport( reason ); } } protected void closeSupport( String reason ) { connected = false; manager.close( this, reason ); } protected boolean isConnected() { return( connected ); } protected void setUnusable() { if ( !is_unusable ){ is_unusable = true; close_time = SystemTime.getMonotonousTime(); } } protected boolean isUnusable() { return( is_unusable ); } protected long getCloseTime() { return( close_time ); } protected void poll() { if ( transport != null ){ transport.poll(); } } protected String getState() { return( "sent=" + DisplayFormatters.formatByteCountToKiBEtc( total_sent ) + ", received=" + DisplayFormatters.formatByteCountToKiBEtc( total_received ) + ", writable=" + is_writable + ", last_w_buff=" + last_write_buff + ", last_w=" + last_write + ", last_r_buff=" + last_read_buff + ", last_r=" + last_read + ", read_pend=" + getReceivePendingSize()); } public String getString() { return( remote_address + ", socket=" + utp_socket + ", con_id" + con_id + " - " + getState()); } }