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

Source Code of com.aelitis.azureus.core.networkmanager.impl.http.HTTPNetworkConnection

/*
* Created on 3 Oct 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 63.529,40 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/

package com.aelitis.azureus.core.networkmanager.impl.http;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;

import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.disk.DiskManager;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.peer.impl.PEPeerControl;
import org.gudy.azureus2.core3.peer.impl.PEPeerTransport;
import org.gudy.azureus2.core3.peer.util.PeerUtils;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.DirectByteBuffer;
import org.gudy.azureus2.core3.util.SimpleTimer;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TimeFormatter;
import org.gudy.azureus2.core3.util.TimerEvent;
import org.gudy.azureus2.core3.util.TimerEventPerformer;

import com.aelitis.azureus.core.networkmanager.NetworkConnection;
import com.aelitis.azureus.core.networkmanager.OutgoingMessageQueue;
import com.aelitis.azureus.core.networkmanager.RawMessage;
import com.aelitis.azureus.core.networkmanager.impl.RawMessageImpl;
import com.aelitis.azureus.core.peermanager.messaging.Message;
import com.aelitis.azureus.core.peermanager.messaging.bittorrent.BTBitfield;
import com.aelitis.azureus.core.peermanager.messaging.bittorrent.BTHandshake;
import com.aelitis.azureus.core.peermanager.messaging.bittorrent.BTHave;
import com.aelitis.azureus.core.peermanager.messaging.bittorrent.BTInterested;
import com.aelitis.azureus.core.peermanager.messaging.bittorrent.BTPiece;
import com.aelitis.azureus.core.peermanager.messaging.bittorrent.BTRequest;
import com.aelitis.azureus.core.util.CopyOnWriteList;
import com.aelitis.azureus.core.util.HTTPUtils;

public abstract class
HTTPNetworkConnection
{
  protected static final LogIDs LOGID = LogIDs.NWMAN;

  private static final int  MAX_OUTSTANDING_BT_REQUESTS  = 16;
 
  protected static final String  NL      = "\r\n";

  private static final String  HDR_SERVER         = "Server: " + Constants.AZUREUS_NAME + " " + Constants.AZUREUS_VERSION + NL;
  private static final String HDR_KEEP_ALIVE_TIMEOUT   = "Keep-Alive: timeout=30" + NL;
  private static final String HDR_CACHE_CONTROL    = "Cache-Control: public, max-age=86400" + NL;

  private static final String  DEFAULT_CONTENT_TYPE  = HTTPUtils.guessContentTypeFromFileType(null);
 
  private static int        max_read_block_size;

  static{
 
      ParameterListener param_listener = new ParameterListener() {
              public void
              parameterChanged(
                  String  str )
              {
                  max_read_block_size = COConfigurationManager.getIntParameter( "BT Request Max Block Size" );
              }
      };
 
      COConfigurationManager.addAndFireParameterListener( "BT Request Max Block Size", param_listener);
  }
 
  private static final int  TIMEOUT_CHECK_PERIOD      = 15*1000;
  private static final int  DEAD_CONNECTION_TIMEOUT_PERIOD  = 30*1000;
  private static final int  MAX_CON_PER_ENDPOINT      = 5*1000;

  private static Map<networkConnectionKey,List<HTTPNetworkConnection>>  http_connection_map = new HashMap<networkConnectionKey,List<HTTPNetworkConnection>>();
 
  static{
    SimpleTimer.addPeriodicEvent(
      "HTTPNetworkConnection:timer",
      TIMEOUT_CHECK_PERIOD,
      new TimerEventPerformer()
      {
        public void
        perform(
          TimerEvent event )
        {
          synchronized( http_connection_map ){
           
            boolean   check = true;
           
            while( check ){
             
              check = false;
 
              Iterator<Map.Entry<networkConnectionKey,List<HTTPNetworkConnection>>>  it = http_connection_map.entrySet().iterator();
             
              while( it.hasNext()){
               
                Map.Entry<networkConnectionKey,List<HTTPNetworkConnection>>  entry = it.next();
               
                networkConnectionKey  key = (networkConnectionKey)entry.getKey();
               
                List<HTTPNetworkConnection>  connections = entry.getValue();
               
                /*
                String  times = "";
               
                for (int i=0;i<connections.size();i++){
                 
                  HTTPNetworkConnection  connection = (HTTPNetworkConnection)connections.get(i);
               
                  times += (i==0?"":",") + connection.getTimeSinceLastActivity();
                }
               
                System.out.println( "HTTPNC: " + key.getName() + " -> " + connections.size() + " - " + times );
                */
               
                if ( checkConnections( connections )){
                 
                    // might have a concurrent mod to the iterator
                 
                  if ( !http_connection_map.containsKey( key )){
                   
                    check  = true;
                   
                    break;
                  }
                }
              }
            }
          }
        }
      });
  }
 
  protected static boolean
  checkConnections(
    List<HTTPNetworkConnection>  connections )
  {
    boolean  some_closed = false;
       
    HTTPNetworkConnection  oldest       = null;
    long          oldest_time    = -1;
   
    Iterator<HTTPNetworkConnection>  it = connections.iterator();
     
    List<HTTPNetworkConnection>  timed_out = new ArrayList<HTTPNetworkConnection>();
   
    while( it.hasNext()){
     
      HTTPNetworkConnection  connection = (HTTPNetworkConnection)it.next();
   
      long  time = connection.getTimeSinceLastActivity();
   
      if ( time > DEAD_CONNECTION_TIMEOUT_PERIOD ){
       
        if ( connection.getRequestCount() == 0 ){
                               
          timed_out.add( connection );
         
          continue;
        }
      }
           
      if ( time > oldest_time && !connection.isClosing()){
         
        oldest_time    = time;
         
        oldest  = connection;
      }
    }
   
    for (int i=0;i<timed_out.size();i++){
     
      ((HTTPNetworkConnection)timed_out.get(i)).close( "Timeout" );
     
      some_closed  = true;
    }
   
    if ( connections.size() - timed_out.size() > MAX_CON_PER_ENDPOINT ){
     
      oldest.close( "Too many connections from initiator");
       
      some_closed  = true;
    }
   
    return( some_closed );
  }
 
  private HTTPNetworkManager  manager;
  private NetworkConnection  connection;
  private PEPeerTransport    peer;
 
  private HTTPMessageDecoder  decoder;
  private HTTPMessageEncoder  encoder;
 
  private boolean      sent_handshake  = false;
 
  private byte[]  peer_id  = PeerUtils.createWebSeedPeerID();

  private boolean  choked  = true;
 
  private List<httpRequest>    http_requests      = new ArrayList<httpRequest>();
  private List<BTRequest>      choked_requests     = new ArrayList<BTRequest>();
  private List<pendingRequest>  outstanding_requests   = new ArrayList<pendingRequest>();
 
  private BitSet  piece_map  = new BitSet();
 
  private long  last_http_activity_time;
 
  private networkConnectionKey  network_connection_key;
 
  private boolean  closing;
  private boolean  destroyed;
   
  private String  last_modified_date;
  private String  content_type  = DEFAULT_CONTENT_TYPE;
 
  private CopyOnWriteList<requestListener>  request_listeners = null;
 
  protected
  HTTPNetworkConnection(
    HTTPNetworkManager    _manager,
    NetworkConnection    _connection,
    PEPeerTransport      _peer )
  {
    manager      = _manager;
    connection    = _connection;
    peer      = _peer;
   
    DiskManager dm = peer.getManager().getDiskManager();
   
    long  last_modified = 0;
   
    try{
      last_modified = dm.getFiles()[0].getFile(true).lastModified();
           
    }catch( Throwable e ){
    }
   
    last_modified_date = TimeFormatter.getHTTPDate( last_modified );
   
    network_connection_key = new networkConnectionKey();
     
    last_http_activity_time  = SystemTime.getCurrentTime();
   
    decoder  = (HTTPMessageDecoder)connection.getIncomingMessageQueue().getDecoder();
    encoder = (HTTPMessageEncoder)connection.getOutgoingMessageQueue().getEncoder();

    synchronized( http_connection_map ){
           
      List<HTTPNetworkConnection>  connections = http_connection_map.get( network_connection_key );
     
      if ( connections == null ){
       
        connections = new ArrayList<HTTPNetworkConnection>();
       
        http_connection_map.put( network_connection_key, connections );
      }
     
      connections.add( this );
     
      if ( connections.size() > MAX_CON_PER_ENDPOINT ){
       
        checkConnections( connections );
      }
    }
   
      // note that the decoder can synchronously call-back if is preloaded with a header
      // here...
   
    encoder.setConnection( this );
    decoder.setConnection( this );
  }
 
  protected boolean
  isSeed()
  {
    if ( ( !peer.getControl().isSeeding()) || peer.getControl().getHiddenBytes() > 0 ){
     
      if (Logger.isEnabled()){
        Logger.log(new LogEvent(peer,LOGID, "Download is not seeding" ));
      }    
     
      sendAndClose( manager.getNotFound());
     
      return( false );
    }
   
    return( true );
  }
 
  protected void
  setContentType(
    String  ct )
  {
    content_type  = ct;
  }
 
  protected HTTPNetworkManager
  getManager()
  {
    return( manager );
  }
 
  protected NetworkConnection
  getConnection()
  {
    return( connection );
  }
 
  protected PEPeerTransport
  getPeer()
  {
    return( peer );
  }
  protected PEPeerControl
  getPeerControl()
  {
    return( peer.getControl());
  }
 
  protected RawMessage
  encodeChoke()
  {
    synchronized( outstanding_requests ){
     
      choked  = true;
    }
   
    return( null );
  }
 
  protected RawMessage
  encodeUnchoke()
  {   
    synchronized( outstanding_requests ){
     
      choked  = false;
     
      for (int i=0;i<choked_requests.size();i++){
               
        decoder.addMessage((BTRequest)choked_requests.get(i));
      }
     
      choked_requests.clear();
    }
   
    return( null );
  }
 
  protected RawMessage
  encodeBitField()
  {
    decoder.addMessage( new BTInterested((byte)1));
   
    return( null );
  }
 
  protected void
  readWakeup()
  {
    connection.getTransport().setReadyForRead();
  }

  protected RawMessage
  encodeHandShake(
    Message  message )
  {
    return( null );
  }
 
  protected abstract void
  decodeHeader(
    HTTPMessageDecoder    decoder,
    String          header )
 
    throws IOException;

  protected String
  encodeHeader(
    httpRequest  request )
  {
    String  current_date = TimeFormatter.getHTTPDate( SystemTime.getCurrentTime());
   
    StringBuffer  res = new StringBuffer(256);
   
    boolean  partial = request.isPartialContent();
   
    res.append( "HTTP/1.1 " );
    res.append( partial?"206 Partial Content":"200 OK" );
      res.append( NL );

    res.append( "Content-Type: " );
    res.append( content_type );
       res.append( NL );   
      
    res.append( "Date: " );
    res.append( current_date );
       res.append( NL );
      
    res.append( "Last-Modified: " );
    res.append( last_modified_date );
      res.append( NL );

    res.append( HDR_CACHE_CONTROL );
   
      // not sure about ETag. I was going to use the torrent hash but I don't understand the link
      // between URL, range requests and ETags. Do we need to generate different ETags for each
      // webseed piece request URL or can we use the torrent hash and rely on the fact that the
      // URL changes? Are range-requests irrelevant as far as ETags go - I'd like to think so...
   
    res.append( HDR_SERVER );
   
    if ( partial ){
     
      long[] offsets = request.getOriginalOffsets();
      long[] lengths = request.getOriginalLengths();
     
      long content_length = request.getContentLength();
     
      if ( offsets.length == 1 && content_length > 0 ){
       
        res.append( "Content-Range: bytes " + offsets[0] + "-" + (offsets[0]+lengths[0]-1) + "/" + content_length );
        res.append( NL );
      }
    }
    res.append( "Connection: " );
    res.append( request.keepAlive()?"Keep-Alive":"Close" );
      res.append( NL );
   
    if ( request.keepAlive()){
       
      res.append( HDR_KEEP_ALIVE_TIMEOUT );
    }
   
    res.append( "Content-Length: " );
    res.append( request.getTotalLength());
    res.append( NL );
   
    res.append( NL );
           
    return( res.toString());
  }
 
  protected void
  addRequest(
    httpRequest    request )
 
    throws IOException
  {
    last_http_activity_time  = SystemTime.getCurrentTime();
   
    PEPeerControl  control = getPeerControl();
   
    if ( !sent_handshake ){
     
      sent_handshake  = true;
     
      decoder.addMessage( new BTHandshake( control.getHash(), peer_id, false, (byte)1 ));
     
      byte[]  bits = new byte[(control.getPieces().length +7) /8];
     
      DirectByteBuffer buffer = new DirectByteBuffer( ByteBuffer.wrap( bits ));
     
      decoder.addMessage( new BTBitfield( buffer, (byte)1 ));
    }
   
    synchronized( outstanding_requests ){

      http_requests.add( request );
    }
   
    submitBTRequests();
  }
 
  protected void
  submitBTRequests()
 
    throws IOException
  {
    PEPeerControl  control = getPeerControl();

    long  piece_size = control.getPieceLength(0);
 
    synchronized( outstanding_requests ){

      while( outstanding_requests.size() < MAX_OUTSTANDING_BT_REQUESTS && http_requests.size() > 0 ){
       
        httpRequest  http_request = (httpRequest)http_requests.get(0);
       
        long[]  offsets  = http_request.getModifiableOffsets();
        long[]  lengths  = http_request.getModifiableLengths();
       
        int  index  = http_request.getIndex();
       
        long  offset   = offsets[index];
        long  length  = lengths[index];
       
        int    this_piece_number   = (int)(offset / piece_size);
        int    this_piece_size    = control.getPieceLength( this_piece_number );
       
        int    offset_in_piece   = (int)( offset - ( this_piece_number * piece_size ));
       
        int    space_this_piece   = this_piece_size - offset_in_piece;
       
        int    request_size = (int)Math.min( length, space_this_piece );
       
        request_size = Math.min( request_size, max_read_block_size );
       
        addBTRequest(
          new BTRequest(
              this_piece_number,
              offset_in_piece,
              request_size,
              (byte)1),
          http_request );
         
        if ( request_size == length ){
         
          if ( index == offsets.length - 1 ){
           
            http_requests.remove(0);
           
          }else{
           
            http_request.setIndex( index+1 );
          }
        }else{
          offsets[index] += request_size;
          lengths[index] -= request_size;
        }
      }
    }
  }
 
  protected void
  addBTRequest(
    BTRequest    request,
    httpRequest    http_request )
 
    throws IOException
  {
    synchronized( outstanding_requests ){
       
      if ( destroyed ){
       
        throw( new IOException( "HTTP connection destroyed" ));
      }
     
      outstanding_requests.add( new pendingRequest( request, http_request ));
     
      if ( choked ){
         
        if ( choked_requests.size() > 1024 ){
         
          Debug.out( "pending request limit exceeded" );
         
        }else{
       
          choked_requests.add( request );
        }
      }else{
       
        decoder.addMessage( request );
      }
    }
  }
 
  protected RawMessage[]
  encodePiece(
    Message    message )
  {
    last_http_activity_time  = SystemTime.getCurrentTime();
   
    BTPiece  piece = (BTPiece)message;
   
    List<pendingRequest>  ready_requests = new ArrayList<pendingRequest>();
   
    boolean  found = false;
   
    synchronized( outstanding_requests ){

      if ( destroyed ){
       
        return( new RawMessage[]{ getEmptyRawMessage( message )});
      }
   
      for (int i=0;i<outstanding_requests.size();i++){
       
        pendingRequest  req = outstanding_requests.get(i);
       
        if (   req.getPieceNumber() == piece.getPieceNumber() &&
            req.getStart()   == piece.getPieceOffset() &&
            req.getLength() == piece.getPieceData().remaining( DirectByteBuffer.SS_NET )){
   
          if ( req.getBTPiece() == null ){
         
            req.setBTPiece( piece );
           
            found  = true;
           
            if ( i == 0 ){
             
              Iterator<pendingRequest>  it = outstanding_requests.iterator();
             
              while( it.hasNext()){
               
                pendingRequest r = it.next();
               
                BTPiece  btp = r.getBTPiece();
               
                if ( btp == null ){
                 
                  break;
                }
               
                it.remove();
               
                ready_requests.add( r );
              }
            }
         
            break;
          }
        }
      }
    }
   
    if ( !found ){
     
      Debug.out( "request not matched" );
     
      return( new RawMessage[]{ getEmptyRawMessage( message )});
    }
   
    if ( ready_requests.size() == 0 ){
     
      return( new RawMessage[]{ getEmptyRawMessage( message )});
    }
   
    try{
      submitBTRequests();
     
    }catch( IOException e ){
     
    }
   
    pendingRequest req  = (pendingRequest)ready_requests.get(0);
   
    DirectByteBuffer[]  buffers;
   
    httpRequest  http_request = req.getHTTPRequest();
   
    RawMessage[]  raw_messages = new RawMessage[ ready_requests.size()];
   
    for (int i=0;i<raw_messages.length;i++){
     
      buffers = new DirectByteBuffer[ 2 ];

      if ( !http_request.hasSentFirstReply()){
   
        http_request.setSentFirstReply();
           
        String  header = encodeHeader( http_request );
     
        buffers[0] = new DirectByteBuffer( ByteBuffer.wrap( header.getBytes()));
     
      }else{
     
          // we have to do this as core code assumes buffer entry 0 is protocol
     
        buffers[0] = new DirectByteBuffer( ByteBuffer.allocate(0));
      }
         
      req  = (pendingRequest)ready_requests.get(i);

      BTPiece  this_piece = req.getBTPiece();
     
      int  piece_number = this_piece.getPieceNumber();
     
      if ( !piece_map.get( piece_number )){
       
          // kinda crappy as it triggers on first block of piece, however better
          // than nothing
       
        piece_map.set( piece_number );
       
        decoder.addMessage( new BTHave( piece_number, (byte)1 ));
      }
     
      buffers[1] = this_piece.getPieceData();
     
      req.logQueued();
     
      if ( request_listeners != null ){
       
        Iterator<requestListener> it = request_listeners.iterator();
     
        while( it.hasNext()){
         
          ((requestListener)it.next()).requestComplete( req );
        }
      }
     
      raw_messages[i] =
        new RawMessageImpl(
            this_piece,
            buffers,
            RawMessage.PRIORITY_HIGH,
            true,
            new Message[0] );
    }
   
    return( raw_messages );
  }
 
  protected int
  getRequestCount()
  {
    synchronized( outstanding_requests ){

      return( http_requests.size());
    }
  }
 
  protected boolean
  isClosing()
  {
    return( closing );
  }
 
  protected void
  close(
    String  reason )
  {
    closing  = true;
   
    peer.getControl().removePeer( peer );
  }
 
  protected void
  destroy()
  {
    synchronized( http_connection_map ){

      List<HTTPNetworkConnection>  connections = http_connection_map.get( network_connection_key );
     
      if ( connections != null ){
       
        connections.remove( this );
       
        if ( connections.size() == 0 ){
         
          http_connection_map.remove( network_connection_key );
        }
      }
    }
   
    synchronized( outstanding_requests ){

      destroyed  = true;
     
      for (int i=0;i<outstanding_requests.size();i++){
       
        pendingRequest  req = (pendingRequest)outstanding_requests.get(i);
       
        BTPiece  piece = req.getBTPiece();
       
        if ( piece != null ){
         
          piece.destroy();
        }
      }
     
      outstanding_requests.clear();
     
      for (int i=0;i<choked_requests.size();i++){
       
        BTRequest  req = BTRequest)choked_requests.get(i);
               
        req.destroy();
      }
     
      choked_requests.clear();
    }
  }
 
  protected long
  getTimeSinceLastActivity()
  {
    long  now = SystemTime.getCurrentTime();
   
    if ( now < last_http_activity_time ){
     
      last_http_activity_time = now;
    }
   
    return( now - last_http_activity_time );
  }
 
  protected void
  log(
    String  str )
  {
    if (Logger.isEnabled()){
      Logger.log(new LogEvent( getPeer(),LOGID, str));
    }  
  }
 
  protected RawMessage
  getEmptyRawMessage(
    Message  message )
  {   
    return(
      new RawMessageImpl(
          message,
          new DirectByteBuffer[]{ new DirectByteBuffer( ByteBuffer.allocate(0))},
          RawMessage.PRIORITY_HIGH,
          true,
          new Message[0] ));
  }
 
  protected void
  sendAndClose(
    String    data )
  {
    final Message  http_message = new HTTPMessage( data );
   
    getConnection().getOutgoingMessageQueue().registerQueueListener(
      new OutgoingMessageQueue.MessageQueueListener()
      {
        public boolean
        messageAdded(
          Message message )
        { 
          return( true );
        }
          
        public void
        messageQueued(
          Message message )
        {     
        }
           
        public void
        messageRemoved(
          Message message )
        {
        }
           
        public void
        messageSent(
          Message message )
        {
          if ( message == http_message ){
           
            close( "Close after message send complete" );
          }
        }
           
          public void
          protocolBytesSent(
            int byte_count )
          { 
          }
        
          public void
          dataBytesSent(
            int byte_count )
          { 
          }
         
          public void flush(){}
      });
   
    getConnection().getOutgoingMessageQueue().addMessage( http_message, false );
  }
 
  protected void
  flushRequests(
    final flushListener    l )
  {
    boolean  sync_fire = false;
   
    synchronized( outstanding_requests ){

      final int request_count = outstanding_requests.size();
           
      if ( request_count == 0 ){
       
        sync_fire = true;
       
      }else{
       
        if ( request_listeners == null ){
         
          request_listeners = new CopyOnWriteList<requestListener>();
        }
       
        request_listeners.add(
          new requestListener()
          {
            int  num_to_go = request_count;
           
            public void
            requestComplete(
              pendingRequest r )
            {
              num_to_go--;
             
              if ( num_to_go == 0 ){
               
                request_listeners.remove( this );
               
                flushRequestsSupport( l );
              }
            }
          });
      }
    }
   
    if ( sync_fire ){
     
      flushRequestsSupport( l );
    }
  }
 
  protected void
  flushRequestsSupport(
    final flushListener    l )
  {
    OutgoingMessageQueue omq = getConnection().getOutgoingMessageQueue();
   
    final Message  http_message = new HTTPMessage( new byte[0] );
   
    omq.registerQueueListener(
      new OutgoingMessageQueue.MessageQueueListener()
      {
        public boolean
        messageAdded(
          Message message )
        { 
          return( true );
        }
          
        public void
        messageQueued(
          Message message )
        {     
        }
           
        public void
        messageRemoved(
          Message message )
        {
        }
           
        public void
        messageSent(
          Message message )
        {
          if ( message == http_message ){
           
            l.flushed();
          }
        }
           
          public void
          protocolBytesSent(
            int byte_count )
          { 
          }
        
          public void
          dataBytesSent(
            int byte_count )
          { 
          }
         
          public void flush(){}
      });
   
    omq.addMessage( http_message, false );
   
      // if after adding the message there's no bytes on the queue then we need to trigger an
      // immediate flushed event as the queue won't get processed (0 bytes on it...)
   
    if ( omq.getTotalSize() == 0 ){
     
      l.flushed();
    }
  }
 
  protected class
  httpRequest
  {
    private final long[]  orig_offsets;
    private final long[]  orig_lengths;   
    private final long    content_length;
    private final boolean  partial_content;
    private final boolean  keep_alive;

    private final long[]  mod_offsets;
    private final long[]  mod_lengths;

    private int    index;
    private long  total_length;
    private boolean  sent_first_reply;
       
    protected
    httpRequest(
      long[]    _offsets,
      long[]    _lengths,
      long    _content_length,
      boolean    _partial_content,
      boolean    _keep_alive )
    {
      orig_offsets  = _offsets;
      orig_lengths  = _lengths;
      content_length  = _content_length;
      partial_content  = _partial_content;
      keep_alive    = _keep_alive;
     
      /*
      String  str ="";
      for (int i=0;i<lengths.length;i++){ 
        str += (i==0?"":",") +"[" + offsets[i] + "/" + lengths[i] + "]";
      }
      System.out.println( network_connection_key.getName() + ": requested " + str + ",part=" + partial_content +",ka=" + keep_alive );
      */
     
      mod_offsets = orig_offsets.clone();
      mod_lengths = orig_lengths.clone();
     
      for (int i=0;i<orig_lengths.length;i++){
       
        total_length += orig_lengths[i];
      }
    }
       
    protected boolean
    isPartialContent()
    {
      return( partial_content );
    }
   
    protected long
    getContentLength()
    {
      return( content_length );
    }
   
    protected boolean
    hasSentFirstReply()
    {
      return( sent_first_reply );
    }
   
    protected void
    setSentFirstReply()
    {
      sent_first_reply  = true;
    }
   
    protected long[]
    getOriginalOffsets()
    {
      return( orig_offsets );
    }
   
    protected long[]
       getOriginalLengths()
       {
         return( orig_lengths );
       }
   
    protected long[]
       getModifiableOffsets()
       {
         return( mod_offsets );
       }
      
       protected long[]
      getModifiableLengths()
      {
        return( mod_lengths );
      }
              
    protected int
    getIndex()
    {
      return( index );
    }
   
    protected void
    setIndex(
      int  _index )
    {
      index = _index;
    }
   
    protected long
    getTotalLength()
    {
      return( total_length );
    }
   
    protected boolean
    keepAlive()
    {
      return( keep_alive );
    }
  }
 
  protected interface
  flushListener
  {
    public void
    flushed();
  }
 
  protected interface
  requestListener
  {
    public void
    requestComplete(
      pendingRequest  request );
  }
 
  protected class
  pendingRequest
  {
    private int  piece;
    private int  start;
    private int  length;
       
    private httpRequest  http_request;
   
    private BTPiece  bt_piece;
       
    protected
    pendingRequest(
      BTRequest    _request,
      httpRequest    _http_request )
    {
      piece  = _request.getPieceNumber();
      start  = _request.getPieceOffset();
      length  = _request.getLength();
     
      http_request  = _http_request;
     
      /*
      if ( peer.getIp().equals( "64.71.5.2")){
       
        TimeFormatter.milliTrace(
            "http_req_create: " +
              piece + "/" + start +
              " [hr=" + http_requests.size() +
              ",cr=" + choked_requests.size() +
              ",or=" + outstanding_requests.size() +
              ",d=" + decoder.getQueueSize() + "]" );
      }
      */
    }
   
    protected int
    getPieceNumber()
    {
      return( piece );
    }
   
    protected int
    getStart()
    {
      return( start );
    }
   
    protected int
    getLength()
    {
      return( length );
    }
   
    protected httpRequest
    getHTTPRequest()
    {
      return( http_request );
    }
   
    protected BTPiece
    getBTPiece()
    {
      return( bt_piece );
    }
   
    protected void
    setBTPiece(
      BTPiece  _bt_piece )
    {
      bt_piece  = _bt_piece;
     
      /*
      if ( peer.getIp().equals( "64.71.5.2")){

        TimeFormatter.milliTrace(
          "http_req_data: " +
            piece + "/" + start +
            " [hr=" + http_requests.size() +
            ",cr=" + choked_requests.size() +
            ",or=" + outstanding_requests.size() +
            ",d=" + decoder.getQueueSize() + "]" );
      }
      */
    }
   
    protected void
    logQueued()
    {
      /*
      if ( peer.getIp().equals( "64.71.5.2")){

        TimeFormatter.milliTrace(
          "http_req_out: " +
            piece + "/" + start +
            " [hr=" + http_requests.size() +
            ",cr=" + choked_requests.size() +
            ",or=" + outstanding_requests.size() +
            ",d=" + decoder.getQueueSize() + "]" );
      }
      */
    }
  }
 
  protected class
  networkConnectionKey
  {
    public boolean
    equals(Object obj)
    {
      networkConnectionKey  other = (networkConnectionKey)obj;
     
      return( Arrays.equals( getAddress(), other.getAddress()) &&
          Arrays.equals(getHash(),other.getHash()))
    }
     
    protected String
    getName()
    {
      return( peer.getControl().getDisplayName() + ": " + connection.getEndpoint().getNotionalAddress().getAddress().getHostAddress());
    }
   
    protected byte[]
    getAddress()
    {
      return( connection.getEndpoint().getNotionalAddress().getAddress().getAddress());
    }
   
    protected byte[]
    getHash()
    {
      return( peer.getControl().getHash());
    }
   
    public int
    hashCode()
    {
      return( peer.getControl().hashCode());

    }
  }
}
TOP

Related Classes of com.aelitis.azureus.core.networkmanager.impl.http.HTTPNetworkConnection

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.