Package dijjer.io.xfer

Source Code of dijjer.io.xfer.BlockTransmitter

/*
* Dijjer - A Peer to Peer HTTP Cache
* Copyright (C) 2004,2005 Change.Tv, Inc
*
* 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
*/
package dijjer.io.xfer;

import java.util.Iterator;
import java.util.LinkedList;
import dijjer.Dijjer;
import dijjer.io.comm.DMT;
import dijjer.io.comm.Message;
import dijjer.io.comm.MessageFilter;
import dijjer.io.comm.Peer;
import dijjer.io.comm.UdpSocketManager;
import dijjer.util.BitArray;
import dijjer.util.logging.Logger;

/**
* @author ian
*
* To change the template for this generated type comment go to Window - Preferences - Java - Code Generation - Code and
* Comments
*/
public class BlockTransmitter {

  public static final int WAIT_AFTER_ALL_SENT = 10000;
  UdpSocketManager _usm;
  Peer _dest;
  int _uid;
  PartiallyReceivedBlock _prb;
  boolean _allReceived = false;
  BitArray _sent = new BitArray(Dijjer.PACKETS_IN_BLOCK);
  Thread _senderThread;
  PacketThrottle _throttle;
  long _lastPacketSendTime;

  public BlockTransmitter(UdpSocketManager usm, Peer destination, int uid, PartiallyReceivedBlock source) {
    _usm = usm;
    _dest = destination;
    _uid = uid;
    _prb = source;
    _throttle = PacketThrottle.getThrottle(_dest);
  }

  public int getNumSent() {
    int ttl = 0;
    for (int x = 0; x < _sent.getSize(); x++) {
      if (_sent.bitAt(x)) {
        ttl++;
      }
    }
    return ttl;
  }

  public void send() {
    startReceiverThread();
    _prb.addListener(new PartiallyReceivedBlock.PacketReceivedListener() {

      public void packetReceived(int packetNo) {
        synchronized (BlockTransmitter.this) {
          BlockTransmitter.this.notify();
        }
      }

      public void receiveAborted(int reason, String description) {
        _usm.send(_dest, DMT.createSendAborted(_uid, description));
        synchronized (BlockTransmitter.this) {
          BlockTransmitter.this.notify();
        }
      }
    });
    sendloop: while (!isFinished()) { synchronized(this) {
      // Synchronize on this for the entire loop. This way we don't have to check on
      // isFinished so much since it will only change between loops and during the wait calls.
      // Also, if we have to wait at all we start through the loop again to see if the delay
      // has been updated with a missing packet message.

      // Wait until we are allowed to send a packet according to throttle
      long lTime = System.currentTimeMillis();
      long currentDelay = lTime - _lastPacketSendTime;
      long remainingDelay = _throttle.getDelay() - currentDelay;
      if (remainingDelay > 50) {
        System.out.println("CCC timeout:"+remainingDelay);
        try {
          this.wait(remainingDelay);
        } catch (InterruptedException e) {
          if (isFinished()) break sendloop;
        }
        continue sendloop;
      }
      lTime = System.currentTimeMillis() - lTime;
      if (lTime > 3000) {
        Logger.warning("Waited " + lTime + "ms due to bandwidth limiting (uid: " + _uid + ")");
      }
      // Check to see if any packets are available to send, or wait until they are or
      // the PRB is aborted
      int nextToSend = -1;
      lTime = System.currentTimeMillis();
      for (int x = 0; x < Dijjer.PACKETS_IN_BLOCK; x++) {
        if (_prb.isReceived(x) && !_sent.bitAt(x)) {
          nextToSend = x;
          break;
        }
      }
      if (nextToSend == -1) {
        try {
          this.wait();
        } catch (InterruptedException e) {
          if (isFinished()) break sendloop;
        }
        continue sendloop;
      }
      lTime = System.currentTimeMillis() - lTime;
      if (lTime > 3000) {
        Logger.warning("Waited " + lTime + "ms due to suitable packet unavailability (uid: " + _uid + ")");
      }
      _lastPacketSendTime = System.currentTimeMillis();
      _throttle.notifyOfPacketSent();
      _usm.send(_dest, DMT.createPacketTransmit(_uid, nextToSend, _sent, _prb.getPacket(nextToSend)));
      _sent.setBit(nextToSend, true);
    }} //end synchronized and sendloop
  }

  protected boolean isFinished() {
    if (_allReceived) {
      return true;
    }
    if (_prb.isAborted()) {
      return true;
    }
    if ((getNumSent() == Dijjer.PACKETS_IN_BLOCK)
        && (System.currentTimeMillis() - _lastPacketSendTime > WAIT_AFTER_ALL_SENT)) {
      return true;
    }
    return false;
  }

  protected void startReceiverThread() {
    (new Thread() {

      public void run() {
        while (!isFinished()) {
          Message msg = _usm.waitFor((MessageFilter.create(10000, DMT.missingPacketNotification)
              .addType(DMT.allReceived)).setField(DMT.UID, _uid));
          if (msg != null) {
            if (msg.getSpec().equals(DMT.missingPacketNotification)) {
              if (_prb.isAborted()) {
                _usm.send(_dest, DMT.createSendAborted(_prb.getAbortReason(), _prb
                    .getAbortDescription()));
              } else {
                LinkedList missing = (LinkedList) msg.getObject(DMT.MISSING);
                if (missing.size() > 50) {
                  Logger.warning("Received large missing packet notification from " + _dest
                      + " of size " + missing.size() + " having sent " + getNumSent());
                }
                _throttle.notifyOfPacketLoss(missing.size());
                for (Iterator i = missing.iterator(); i.hasNext();) {
                  Integer packetNo = (Integer) i.next();
                  if (_prb.isReceived(packetNo.intValue())) {
                    _sent.setBit(packetNo.intValue(), false);
                  }
                }
              }
            } else if (msg.getSpec().equals(DMT.allReceived)) {
              _allReceived = true;
            }
            synchronized (BlockTransmitter.this) {
              BlockTransmitter.this.notify();
            }
          }
        }
      }
    }).start();
  }
}
TOP

Related Classes of dijjer.io.xfer.BlockTransmitter

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.