Package rtpi.reliability.ORTA

Source Code of rtpi.reliability.ORTA.ORTA

/* The Java RTP/I library, Version 0.1 alpha.
* This library provides the functionality of RTP/I as it is specified in
* Internet Draft draft-mauve-rtpi-00.txt.
*
* Copyright (C) 2000 Martin Mauve
* University of Mannheim / Germany
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Martin Mauve
*
* e-mail:
* mauve@informatik.uni-mannheim.de
*
* paper mail:
* Martin Mauve
* University of Mannheim
* Lehrstuhl Praktische Informatik IV
* L15, 16
* 68131 Mannheim
* Germany
*/

package rtpi.reliability.ORTA;

import java.net.InetAddress;
import java.io.IOException;

import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Random;
import java.util.Hashtable;
import java.util.Iterator;

import rtpi.reliability.Reliable;
import rtpi.reliability.ReliableRecipient;
import rtpi.reliability.QosNotSupportedException;
import rtpi.IllegalValueException;

import rtpi.packets.RtpiDataPacket;

import rtpi.util.SyncQueue;

import rtpi.transport.TransportRecipient;
import rtpi.transport.orta.ORTATransport;
import rtpi.transport.TransportPacket;

/**
* This is a dummy implementation of the Reliableinterface. It uses UDP
* multicast and does not provide any other QoS than UNRELIABLE. It does also not
* provide redundant transmission. This reliability service uses the IPMCTransport
* class as a foundation for transmitting and receiving packets.
*
* @author Martin Mauve
*/

public final class ORTA extends Thread implements Reliable, TransportRecipient {

    private SyncQueue messages = new SyncQueue();
    private ReliableRecipient recipient = null;
    private ORTATransport transport = null;
    private Hashtable senders = new Hashtable();
    private int bufferTime=0;
    private long lastTimePacketsChecked=System.currentTimeMillis();

    /**
     * Create a new instance of UdpUnreliable.
     *
     * @param taddr The multicast address that is used to transmit and receive the packets.
     * @param tport The port.
     * @param rate The maximum datrate at which packets may be sent. This rate is
     *             enforced by traffic shaping in the underlying IPMCTransport. The
     *             datarate is given in bits/second.
     * @param bufferT The maximum time a received packet will be buffered before it is
     *                discarded. Buffering is required when some packets have arrived
     *                for an ADU while others are still missing. A reliability service
     *                hands only complete ADUs to its recipient.
     */

    public ORTA(InetAddress taddr, int tport, int lport, int rate, int bufferT) {
  transport = new ORTATransport(taddr, tport, lport, rate);
  bufferTime = bufferT;
  transport.registerTransportRecipient(this);
  start();
    }

    /**
     * This returns the size of the payload that can
     * be transported in a single packet. This payload
     * size INCLUDES all RTP/I and reliability headers.
     */

    public int getTransportPayloadSize() {
  return transport.getTransportPayloadSize();
    }

    /**
     * This returns the size of the combined RTP/I and
     * reliability headers.
     */

    public int getCombinedHeaderSize() {
  return RtpiDataPacket.HEADER_SIZE;
    }

    public void run() {
 
  Message message=null;

  while (true) {
     
      try {
    message=(Message) messages.get();
      } catch (Exception exe) {
    System.err.println("UdpUnreliable: could not get next message from message queue");
    continue;
      }
     
      switch(message.opCode) {
      case Message.QUIT:
    execQuit(); // clean up!
    return; // return to leave the run method!
      case Message.CONNECTION_CLOSED:
    execConnectionClosed();
    break;
      case Message.RECEIVE_TRANSPORT_PACKET:
    execReceiveTransportPacket((TransportPacket) message.args);
    break;
      case Message.TRANSMIT_RTPI_ADU:
    execTransmitRtpiAdu((LinkedList) message.args);
    break;
      case Message.JOIN_GROUP:
    execJoinGroup();
    break;
      case Message.LEAVE_GROUP:
    execLeaveGroup();
    break;
      case Message.REGISTER_RECIPIENT:
    execRegisterRecipient((ReliableRecipient) message.args);
    break;
      case Message.SET_RATE:
    execSetRate(((Integer) message.args).intValue());
    break;
      default:
    System.err.println("UdpUnreliable: illegal message opcode: "+message.opCode+message.args);
    break;
      }     
  }
    }
   
    /**
     * This terminates the reliability service.
     */

    public void quit(){
  messages.put(new Message(Message.QUIT, null));
    }

    private void execQuit() {
  return;
    }

    /**
     * This method is used to transmit an ADU. The ADU may consist of
     * multiple RTP/I packets if the ADU is too large to fit into a
     * single (network) packet. The RTP/I packets MUST form a single
     * valid RTP/I ADU.
     * As an option the ADU may be transmitted with a certain amount of
     * redundancy that is to be transmitted in a certain time interval
     * to compensate for packet loss. It is important to notice that a
     * given implementation may not support redundancy.
     *
     * @param packet A linked list of the RTP/I packets that belong to a single ADU.
     * @param redundancy The amount of redundancy that should be added to this ADU.
     * @param transmissionInterval The interval during which redundancy information
     *                             may be transmitted.
     */

    public void transmitRtpiAdu(LinkedList packets, float redundancy, int transmissionInterval)
  throws QosNotSupportedException, IllegalValueException {
  if (redundancy!=0) {
      throw new QosNotSupportedException("UdpUnreliable: redundancy not supported by UdpUnreliable");
  }
 
  ListIterator iter = packets.listIterator();
 
  if (!iter.hasNext()) {
      throw new IllegalValueException("UdpUnreliable: empty RTP/I ADU");
  }

  RtpiDataPacket packet = (RtpiDataPacket) iter.next();

  if (packet.getFragmentCount()!=0) {
      throw new IllegalValueException("UdpUnreliable: fragment count of the first packet is not 0");
  }

  int sequenceNumber=packet.getSequenceNumber();
  int fragmentCount=packet.getFragmentCount();
  int type=packet.getType();
  int payloadType=packet.getPayloadType();
  int priority=packet.getPriority();
  int participantID=packet.getParticipantID();
  long subcomponentID=packet.getSubcomponentID();
  long timestamp=packet.getTimestamp();

  while (iter.hasNext()) {
      packet=(RtpiDataPacket) iter.next();
      if (sequenceNumber!=packet.getSequenceNumber()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have different sequence numbers");
      }
      if (((++fragmentCount)%0x0000FFFF)!=packet.getFragmentCount()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have non contiguous fragment counts");
      }
      if (type!=packet.getType()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have different types");
      }
      if (payloadType!=packet.getPayloadType()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have different payload types");
      }
      if (priority!=packet.getPriority()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have different priorities");
      }
      if (participantID!=packet.getParticipantID()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have different paticipant IDs");
      }
      if (subcomponentID!=packet.getSubcomponentID()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have different sub-component IDs");
      }
      if (timestamp!=packet.getTimestamp()) {
    throw new IllegalValueException("UdpUnreliable: packets of the same RTP/I ADU have different timestamps");
      }
  }   

  if (packet.getEnd()!=1) {
      throw new IllegalValueException("UdpUnreliable: end bit not set in last packet of RTP/I ADU");
  }

        messages.put(new Message(Message.TRANSMIT_RTPI_ADU, packets));
    }

    private void execTransmitRtpiAdu(LinkedList packets) {
  ListIterator iter = packets.listIterator();
  RtpiDataPacket packet=null;
 
  while (iter.hasNext()) {
      packet=(RtpiDataPacket) iter.next();
      packet.setReliabilityType(0);
      packet.setExtension(0);
      try {
    packet.flush();
      } catch (Exception ex) {
    System.err.println("UdpUnreliable: error while flushing RtpiDataPacket "+ex);
      }
      TransportPacket tpacket = new TransportPacket(packet.getLength()+
                RtpiDataPacket.HEADER_SIZE, packet.getPacketData());
      transport.sendTransportPacket(tpacket);
  }
    }

    /**
     * This method is called when a transport packet has been received. This
     * packet is checked and if it is the last packet of an ADU, then the ADU
     * is handed to the recipient of this reliability service.
     *
     * @param packet The transport packet that has been received.
     */

    public void receiveTransportPacket(TransportPacket packet){
  messages.put(new Message(Message.RECEIVE_TRANSPORT_PACKET, packet));
    }

    private void execReceiveTransportPacket(TransportPacket tpacket) {
  int position=0;
  do {
      RtpiDataPacket packet = new RtpiDataPacket(tpacket.getData(), position);
      try {
    packet.parse();
      } catch (Exception ex) {
    System.err.println("UdpUnreliable: Exception while parsing RTP/I packet "+ex+" - packet ignored!");
    return;
      }

      if (packet.getReliabilityType()!=0) {
    System.err.println("UdpUnreliable: Illegal reliability type in receive RtpiDataPacket "+
           packet.getReliabilityType()+" - packet ignored!");
    return;
      }

      if (packet.getType()!=RtpiDataPacket.EVENT &&
    packet.getType()!=RtpiDataPacket.STATE &&
    packet.getType()!=RtpiDataPacket.DELTA_STATE &&
    packet.getType()!=RtpiDataPacket.STATE_QUERY) {
    System.err.println("UdpUnreliable: Illegal ADU type in receive RtpiDataPacket "+
           packet.getType()+" - packet ignored!");
    return;
      }

      if (packet.getFragmentCount()==0 && packet.getEnd()==1) {
    LinkedList packets = new LinkedList();
    packets.add(packet);
    recipient.receiveRtpiAdu(packets);
      } else {
    Hashtable subcomponents = (Hashtable) senders.get(new Integer(packet.getParticipantID()));
    if (subcomponents==null) {
        subcomponents = new Hashtable();
        senders.put (new Integer(packet.getParticipantID()),subcomponents);       
        Hashtable aduTypes=new Hashtable();
        subcomponents.put(new Long(packet.getSubcomponentID()),aduTypes);
        Hashtable adus = new Hashtable();
        aduTypes.put(new Long(packet.getType()), adus);
        RtpiDataPacketBuffer buffer = new RtpiDataPacketBuffer(packet);
        adus.put(new Integer(packet.getSequenceNumber()), buffer);
    } else {
        Hashtable aduTypes=(Hashtable) subcomponents.get(new Long(packet.getSubcomponentID()));
        if (aduTypes==null) {
      aduTypes = new Hashtable();
      subcomponents.put(new Long(packet.getSubcomponentID()), aduTypes);
      Hashtable adus = new Hashtable();
      aduTypes.put(new Long(packet.getType()), adus);
      RtpiDataPacketBuffer buffer = new RtpiDataPacketBuffer(packet);
      adus.put(new Integer(packet.getSequenceNumber()), buffer);
        } else {
      Hashtable adus = (Hashtable) aduTypes.get(new Long (packet.getType()));
      if (adus==null) {
          adus = new Hashtable();
          aduTypes.put(new Long(packet.getType()), adus);
          RtpiDataPacketBuffer buffer = new RtpiDataPacketBuffer(packet);
          adus.put(new Integer(packet.getSequenceNumber()), buffer);
      } else {
          RtpiDataPacketBuffer buffer = (RtpiDataPacketBuffer) adus.get(new Integer(packet.getSequenceNumber()));
          if (buffer==null) {
        buffer = new RtpiDataPacketBuffer(packet);
        adus.put(new Integer(packet.getSequenceNumber()), buffer);
          } else {
        buffer.put(packet);
        if (buffer.isComplete()) {
            recipient.receiveRtpiAdu(buffer.getPackets());
            adus.remove(new Integer(packet.getSequenceNumber()));
            if (adus.isEmpty()) { // we remove all empty hashtables this may be inefficient
                            // an optimization could be to keep the tables and delete
                            // them periodically or when the become to memory consumant!
          aduTypes.remove(new Integer(packet.getType()));
          if (aduTypes.isEmpty()) {
              subcomponents.remove(new Long(packet.getSubcomponentID()));
              if (subcomponents.isEmpty()) {
            senders.remove(new Integer(packet.getParticipantID()));
              }
          }
            }
        }
          }
      }
        }
    }
      }
      position+=packet.getLength()+RtpiDataPacket.HEADER_SIZE;
      position+=(4-position%4)%4;
  } while(position < tpacket.getLength());

  removeOutdatedPackets();

    }     

    void removeOutdatedPackets() {
  if (System.currentTimeMillis()-lastTimePacketsChecked<bufferTime) {
      return;
  }
 
  Hashtable subcomponents=null;
  Hashtable aduTypes=null;
  Hashtable adus=null;
  RtpiDataPacketBuffer buf=null;

  for (Iterator senderIt=senders.values().iterator();senderIt.hasNext();) {
      subcomponents = (Hashtable) senderIt.next();
      for (Iterator subcomponentIt=subcomponents.values().iterator();subcomponentIt.hasNext();) {
    aduTypes = (Hashtable) subcomponentIt.next();
    for (Iterator aduTypeIt=aduTypes.values().iterator();aduTypeIt.hasNext();) {
        adus = (Hashtable) aduTypeIt.next();
        for (Iterator aduIt=adus.values().iterator();aduIt.hasNext();) {
      buf = (RtpiDataPacketBuffer) aduIt.next();
      if (buf.timedOut(bufferTime)) {
          System.err.println("UdpUnreliable ADU timed out!!!!!");
          aduIt.remove();
          if (adus.isEmpty()) {
        aduTypeIt.remove();
        if (aduTypes.isEmpty()) {
            subcomponentIt.remove();
            if (subcomponents.isEmpty()) {
          senderIt.remove();
            }
        }
          }
      }
        }
    }
      }
  }

  lastTimePacketsChecked=System.currentTimeMillis();
   

    /**
     * This is called if the undelying IPMCTransport has suffered a fatal error.
     */

    public void connectionClosed() {
  messages.put(new Message(Message.CONNECTION_CLOSED,null));
    }

    private void execConnectionClosed() {
  quit();
  if (recipient!=null) {
      recipient.connectionClosed();
  }
    }
   
    /**
     * This joins the multicast group. This MUST be called before any ADUs can be
     * transmitted or received.
     */
    public void joinGroup() {
  //System.out.println("reliable joinGroup");
  messages.put(new Message(Message.JOIN_GROUP, null));
    }

    private void execJoinGroup() {
  //System.out.println("reliable execjoinGroup");
  try {
      transport.joinGroup();
  } catch (Exception ex) {
      System.err.println("UdpUnreliable: "+ex);
  }
    }

    /**
     * This leaves the multicast group. After this method has been called no ADUs may
     * be transmitted and no further ADUs can be received.
     * However, already received ADUs may still be delivered.
     */
    public void leaveGroup() {
  messages.put(new Message(Message.LEAVE_GROUP, null));
    }

    private void execLeaveGroup() {
  transport.leaveGroup();
    }

    /**
     * This registers the recipient of the ADUs and
     * loss notifications.
     *
     * @param rec The reipient.
     */

    public void registerRecipient(ReliableRecipient rec) {
  messages.put(new Message(Message.REGISTER_RECIPIENT, rec));
    }

    private void execRegisterRecipient(ReliableRecipient rec) {
  recipient = rec;
  transport.registerTransportRecipient(this);
    }

    /**
     * This sets the maximum datarate of the underlying IPMCTransport.
     *
     * @param The new rate in bits/second.
     */

    public void setRate(int rate) {
  messages.put(new Message(Message.SET_RATE, new Integer(rate)));
    }

    private void execSetRate(int rate) {
  transport.setRate(rate);
    }

    /**
     * This method is used to set the QoS for a given subcomponent and
     * RTP/I ADU type pair. It is important to notice that a given implementation
     * of the Reliable interface may only support certain QoS settings.
     *
     * @param subcomponentID The ID of the subcomponent.
     * @param type The RTP/I ADU type.
     * @param qos The desired QoS.
     */

    public void setInterest(long subcomponentID, int type, int qos) throws QosNotSupportedException {
  if (qos!=Reliable.NONE) {
      throw new QosNotSupportedException("UdpUnreliable: only NONE qos supported");
  }
    }
   
    /**
     * This method is used to set a default QoS for all subcomponent and
     * RTP/I ADU type pairs to which no other QoS has been specified.
     * It is important to notice that a given implementation
     * of the Reliable interface may only support certain QoS settings.
     *
     * @param subcomponentID The ID of the subcomponent.
     * @param type The RTP/I ADU type.
     * @param qos The desired QoS.
     */

    public void setDefaultInterest(int type, int qos) throws QosNotSupportedException {
  if (qos!=Reliable.NONE) {
      throw new QosNotSupportedException("UdpUnreliable: only NONE qos supported");
  }
    }
}

   

   
TOP

Related Classes of rtpi.reliability.ORTA.ORTA

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.