Package com.aelitis.azureus.core.networkmanager.impl.udp

Source Code of com.aelitis.azureus.core.networkmanager.impl.udp.UDPTransportHelper

/*
* Created on 22 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 com.aelitis.azureus.core.networkmanager.impl.udp;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import org.gudy.azureus2.core3.util.Debug;

import com.aelitis.azureus.core.networkmanager.impl.TransportHelper;

public class
UDPTransportHelper
  implements TransportHelper
{
  public static final int READ_TIMEOUT    = 30*1000;
  public static final int CONNECT_TIMEOUT    = 20*1000;
 
  private UDPConnectionManager  manager;
  private UDPSelector        selector;
  private InetSocketAddress    address;
  private UDPTransport      transport;
 
  private boolean          incoming;
 
  private UDPConnection      connection;
 
  private selectListener    read_listener;
  private Object        read_attachment;
  private boolean       read_selects_paused;
 
  private selectListener    write_listener;
  private Object        write_attachment;
  private boolean       write_selects_paused  = true// default is paused

  private boolean        closed;
  private IOException      failed;
 
  private ByteBuffer[]    pending_partial_writes;
   
  private Map  user_data;
 
  public
  UDPTransportHelper(
    UDPConnectionManager  _manager,
    InetSocketAddress    _address,
    UDPTransport      _transport )
 
    throws IOException
  {
      // outgoing
 
    manager    = _manager;
    address   = _address;
    transport  = _transport;
   
    incoming  = false;
   
    connection   = manager.registerOutgoing( this );
   
    selector  = connection.getSelector();

  }
 
  public
  UDPTransportHelper(
    UDPConnectionManager  _manager,
    InetSocketAddress    _address,
    UDPConnection      _connection )
  {
      // incoming
     
    manager    = _manager;
    address   = _address;
    connection = _connection;
 
    incoming  = true;
   
    selector  = connection.getSelector();
  }
 
  protected void
  setTransport(
    UDPTransport  _transport )
  {
    transport  = _transport;
  }

  protected UDPTransport
  getTransport()
  {
    return( transport );
  }
 
  protected int
  getMss()
  {
    if ( transport == null ){
     
      return( UDPNetworkManager.getUdpMssSize());
    }
   
    return( transport.getMssSize());
  }
 
  public boolean
  minimiseOverheads()
  {
    return( UDPNetworkManager.MINIMISE_OVERHEADS );
  }
 
  public int
  getConnectTimeout()
  {
    return( CONNECT_TIMEOUT );
  }
 
  public int
  getReadTimeout()
  {
    return( READ_TIMEOUT );
  }
 
  public InetSocketAddress
  getAddress()
  {
    return( address );
  }
 
  public String
  getName(
    boolean verbose )
  {
    return( "UDP" );
  }
 
  public boolean
  isIncoming()
  {
    return( incoming );
  }
 
  protected UDPConnection
  getConnection()
  {
    return( connection );
  }
 
  public boolean
  delayWrite(
    ByteBuffer buffer)
  {
    if ( pending_partial_writes == null ){
     
      pending_partial_writes = new ByteBuffer[]{ buffer };
     
      return( true );
    }
   
    return( false );
  }
 
  public boolean
  hasDelayedWrite()
  {
    return( pending_partial_writes != null );
  }
 
  public int
  write(
    ByteBuffer   buffer,
    boolean    partial_write )
 
    throws IOException
  {
    synchronized( this ){
     
      if ( failed != null ){
       
        throw( failed );
      }
     
      if ( closed ){
       
        throw( new IOException( "Transport closed" ));
      }
    }
   
    int  buffer_rem = buffer.remaining();
   
    if ( partial_write && buffer_rem < UDPConnectionSet.MIN_WRITE_PAYLOAD ){
     
      if ( pending_partial_writes == null ){
       
        pending_partial_writes = new ByteBuffer[1];
               
        ByteBuffer  copy = ByteBuffer.allocate( buffer_rem );
       
        copy.put( buffer );
       
        copy.position( 0 );
       
        pending_partial_writes[0] = copy;
       
        return( buffer_rem );
       
      }else{
       
        int  queued = 0;
       
        for ( int i=0;i<pending_partial_writes.length;i++){
         
          queued += pending_partial_writes[i].remaining();
        }
       
        if ( queued + buffer_rem <= UDPConnectionSet.MAX_BUFFERED_PAYLOAD ){
         
          ByteBuffer[] new_ppw = new ByteBuffer[ pending_partial_writes.length+1 ];
         
          for (int i=0;i<pending_partial_writes.length;i++){
           
            new_ppw[i] = pending_partial_writes[i];
          }
         
          ByteBuffer  copy = ByteBuffer.allocate( buffer_rem );
         
          copy.put( buffer );
         
          copy.position( 0 );
         
          new_ppw[pending_partial_writes.length] = copy;
         
          pending_partial_writes = new_ppw;
         
          return( buffer_rem );
        }
      }
    }
   
    if ( pending_partial_writes != null ){
     
      int  ppw_len = pending_partial_writes.length;
      int  ppw_rem  = 0;
     
      ByteBuffer[]  buffers2 = new ByteBuffer[ppw_len+1];
     
      for ( int i=0;i<ppw_len;i++){
       
        buffers2[i] = pending_partial_writes[i];
       
        ppw_rem += buffers2[i].remaining();
      }
     
      buffers2[ppw_len] = buffer;
     
      try{
        int written = connection.write( buffers2, 0, buffers2.length );
       
        if ( written >= ppw_rem ){
         
          return( written - ppw_rem );
         
        }else{
         
          return( 0 );
        }
       
      }finally{
       
        ppw_rem  = 0;
       
        for ( int i=0;i<ppw_len;i++){
                   
          ppw_rem += buffers2[i].remaining();
        }
       
        if ( ppw_rem == 0 ){
         
          pending_partial_writes = null;
        }
      }
    }else{
     
      return( connection.write( new ByteBuffer[]{ buffer }, 0, 1 ));
    }
  }

    public long
    write(
      ByteBuffer[]   buffers,
      int       array_offset,
      int       length )
   
      throws IOException
    {
    synchronized( this ){
     
      if ( failed != null ){
       
        throw( failed );
      }
     
      if ( closed ){
       
        throw( new IOException( "Transport closed" ));
      }
    }
   
    if ( pending_partial_writes != null ){
     
      int  ppw_len = pending_partial_writes.length;
      int  ppw_rem  = 0;
     
      ByteBuffer[]  buffers2 = new ByteBuffer[length+ppw_len];
     
      for ( int i=0;i<ppw_len;i++){
       
        buffers2[i] = pending_partial_writes[i];
       
        ppw_rem += buffers2[i].remaining();
      }
     
      int  pos = ppw_len;

      for (int i=array_offset;i<array_offset+length;i++){
       
        buffers2[pos++] = buffers[i];
      }
     
      try{
        int written = connection.write( buffers2, 0, buffers2.length );
       
        if ( written >= ppw_rem ){
         
          return( written - ppw_rem );
         
        }else{
         
          return( 0 );
        }
       
      }finally{
       
        ppw_rem  = 0;
       
        for ( int i=0;i<ppw_len;i++){
                   
          ppw_rem += buffers2[i].remaining();
        }
       
        if ( ppw_rem == 0 ){
         
          pending_partial_writes = null;
        }
      }
    }else{
   
      return( connection.write( buffers, array_offset, length ));
    }
    }

    public int
    read(
      ByteBuffer buffer )
   
      throws IOException
    {
    synchronized( this ){
     
      if ( failed != null ){
       
        throw( failed );
      }
     
      if ( closed ){
       
        throw( new IOException( "Transport closed" ));
      }
    }
   
      return( connection.read( buffer ));
    }

    public long
    read(
      ByteBuffer[]   buffers,
      int       array_offset,
      int       length )
   
      throws IOException
    {
    synchronized( this ){
     
      if ( failed != null ){
       
        throw( failed );
      }
     
      if ( closed ){
       
        throw( new IOException( "Transport closed" ));
      }
    }
   
      long  total = 0;
     
      for (int i=array_offset;i<array_offset+length;i++){
       
        ByteBuffer  buffer = buffers[i];
       
        int  max = buffer.remaining();
       
        int  read = connection.read( buffer );
       
        total += read;
       
        if ( read < max ){
       
          break;
        }
      }
      //System.out.println( "total = " + total );
      return( total );
    }

    protected void
    canRead()
    {
      fireReadSelect();
    }
   
    protected void
    canWrite()
    {
      fireWriteSelect();
    }
   
    public synchronized void
    pauseReadSelects()
    {
      if ( read_listener != null ){
       
        selector.cancel( this, read_listener );
      }
     
      read_selects_paused  = true;
    }
   
    public synchronized void
    pauseWriteSelects()
    {
      if ( write_listener != null ){
       
        selector.cancel( this, write_listener );
      }
     
      write_selects_paused = true;
    }
    public synchronized void
    resumeReadSelects()
    {
      read_selects_paused = false;
     
      fireReadSelect();
    }
   
    public synchronized void
    resumeWriteSelects()
    {
      write_selects_paused = false;
           
      fireWriteSelect();
    }
   
    public void
    registerForReadSelects(
      selectListener  listener,
      Object      attachment )
    {
      synchronized( this ){
       
        read_listener    = listener;
        read_attachment    = attachment;
      }
     
      resumeReadSelects();
    }
   
    public void
    registerForWriteSelects(
      selectListener  listener,
      Object      attachment )
    {
      synchronized( this ){
       
          write_listener    = listener;
        write_attachment  = attachment; 
      }
     
      resumeWriteSelects();
    }
   
    public synchronized void
    cancelReadSelects()
    {
      selector.cancel( this, read_listener );
     
      read_selects_paused  = true;
        read_listener    = null;
      read_attachment    = null;
    }
   
    public synchronized void
    cancelWriteSelects()
    {
         selector.cancel( this, write_listener );
       
      write_selects_paused  = true;
       write_listener      = null;
      write_attachment    = null;
    }
   
    protected void
    fireReadSelect()
    {
       synchronized( this ){
         
         if ( read_listener != null && !read_selects_paused ){
          
           if ( failed != null  ){
            
              selector.ready( this, read_listener, read_attachment, failed );
             
           }else if ( closed ){
            
                selector.ready( this, read_listener, read_attachment, new Throwable( "Transport closed" ));
              
           }else if ( connection.canRead()){
            
              selector.ready( this, read_listener, read_attachment );
           }
         }
       }
    }
    protected void
    fireWriteSelect()
    {
        synchronized( this ){
            
         if ( write_listener != null && !write_selects_paused ){
          
           if ( failed != null  ){
            
             write_selects_paused  = true;
            
              selector.ready( this, write_listener, write_attachment, failed );
             
           }else if ( closed ){
            
             write_selects_paused  = true;

                selector.ready( this, write_listener, write_attachment, new Throwable( "Transport closed" ));

           }else if ( connection.canWrite()){
            
             write_selects_paused  = true;
                         
              selector.ready( this, write_listener, write_attachment );
           }
         }
      }
    }
   
    public void
    failed(
      Throwable  reason )
    {
      synchronized( this ){
           
        if ( reason instanceof IOException ){
         
          failed = (IOException)reason;
         
        }else{
         
          failed  = new IOException( Debug.getNestedExceptionMessageAndStack(reason));
        }
     
        fireReadSelect();
        fireWriteSelect();
      }
     
      connection.failedSupport( reason );
    }
   
  public boolean
  isClosed()
  {
    synchronized( this ){
   
      return( closed );
    }
  }
 
    public void
    close(
      String  reason )
    {
      synchronized( this ){
       
           closed  = true;
          
        fireReadSelect();
          fireWriteSelect();
        }
     
      connection.closeSupport( reason );
    }
   
  protected void
  poll()
  {
       synchronized( this ){
        
         fireReadSelect();
        
         fireWriteSelect();
       }
  }
 
  public synchronized void
  setUserData(
      Object  key,
      Object  data )
  {
    if ( user_data == null ){

      user_data = new HashMap();
    }

    user_data.put( key, data );
  }

  public synchronized Object
  getUserData(
      Object  key )
  {
    if ( user_data == null ){

      return(null);

    }

    return( user_data.get( key ));
  }
 
  public void
  setTrace(
    boolean  on )
  {
  }
 
  public void setScatteringMode(long forBytes) {
    // currently not implemented for UDP   
  }
}
TOP

Related Classes of com.aelitis.azureus.core.networkmanager.impl.udp.UDPTransportHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.