Package org.cipango.server.transaction

Source Code of org.cipango.server.transaction.ServerTransaction

// ========================================================================
// Copyright 2008-2009 NEXCOM Systems
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package org.cipango.server.transaction;

import java.io.IOException;

import org.cipango.server.SipRequest;
import org.cipango.server.SipResponse;
import org.cipango.util.TimerTask;

import org.eclipse.jetty.util.log.Log;

public class ServerTransaction extends Transaction
  // INVITE response retransmit interval
  private static final int TIMER_G = 0;
 
  // Wait time for ACK receipt
  private static final int TIMER_H = 1;
 
  // Wait time for ACK retransmits
  private static final int TIMER_I = 2;
 
  // Wait time for non-INVITE request retransmits
  private static final int TIMER_J = 3;
 
  // Wait time for accepted INVITE request retransmits
  private static final int TIMER_L = 4;

  private static final char[] TIMERS = {'G','H','I','J','L'};
   
  private SipResponse _provisionalResponse;
    private SipResponse _finalResponse;
   
    private ServerTransactionListener _listener;
   
    private long gDelay = __T1;
   
  public ServerTransaction(SipRequest request)
    {
    super(request, request.getTopVia().getBranch());
    _timers = new TimerTask[TIMER_L+1];
   
    setConnection(request.getConnection());
   
    if (isInvite())
      setState(STATE_PROCEEDING);
    else
      setState(STATE_TRYING);
  }
 
    public void setListener(ServerTransactionListener listener)
    {
      if (_listener == null)
        _listener = listener;
    }
   
    public void cancel(SipRequest cancel) throws IOException
    {
       _listener.handleCancel(this, cancel);
    }
   
    public void handleAck(SipRequest ack)
    {
      if (isInvite())
      {
        if (_state != STATE_COMPLETED)
        {
          Log.info("ACK in state {} for transaction {}", getStateAsString(), this);
          return;
        }
        setState(STATE_CONFIRMED);
        cancelTimer(TIMER_H); cancelTimer(TIMER_G);
       
        if (isTransportReliable())
          terminate(); // TIMER_I == 0
        else
          startTimer(TIMER_I, __T4);
      }
      else
      {
        Log.info("ACK for non-INVITE: {}", this);
      }
    }
   
    public void handleRetransmission(SipRequest request)
    {
      // TODO cseq
      SipResponse response = null;
     
      if (_state == STATE_PROCEEDING)
        response = _provisionalResponse;
      else if (_state == STATE_COMPLETED)
        response = _finalResponse;
     
      if (response != null)
      {
        try
        {
          doSend(response);
        }
        catch (Exception e)
        {
          Log.debug(e);
        }
      }
    }
 
  public boolean isServer()
    {
    return true;
  }
 
  public void send(SipResponse response)
    {
    int status = response.getStatus();
   
    if (isInvite())
        {
            switch (_state)
            {
            case STATE_PROCEEDING:
                if (status < 200)
                {
                    _provisionalResponse = response;
                }
                else if (status >= 300)
                {
                    setState(STATE_COMPLETED);
                  _finalResponse = response;

                    if (!isTransportReliable())
                        startTimer(TIMER_G, gDelay);
                   
                    startTimer(TIMER_H, 64*__T1);
                }
                else if (status >= 200)
                {
                  setState(STATE_ACCEPTED);
                  startTimer(TIMER_L, 64*__T1);
                }
                break;
            case STATE_ACCEPTED:
              if (!(status >= 200 && status < 300))
                throw new IllegalStateException("!2xx && Accepted");
              break;
            default:
                throw new IllegalStateException("sendInvite && !Proceeding");
            }
        }
    else
        {
            switch (_state)
            {
            case STATE_TRYING:
            case STATE_PROCEEDING:
                if (response.getStatus() < 200)
                {
                    _provisionalResponse = response;
                    if (_state == STATE_TRYING)
                        setState(STATE_PROCEEDING);                   
                }
                else if (response.getStatus() >= 200)
                {
                    setState(STATE_COMPLETED);
                    _finalResponse = response;

                    if (isTransportReliable())
                        terminate(); // TIMER_J == 0
                    else
                      startTimer(TIMER_J, 64*__T1);
                }
                break;
            default:
                throw new IllegalStateException("sendNonInvite && !(state == Trying || state == Proceeding)");
            }
        }
   
    try
        {
      doSend(response);
        }
    catch (IOException e)
        {
      Log.debug(e);
    }
  }
 
  private void doSend(SipResponse response) throws IOException
    {
    getServer().getConnectorManager().sendResponse(response, getConnection());
  }
 
  public void timeout(int id)
    {
    switch(id)
        {
    case TIMER_G:
      try
            {
        doSend(_finalResponse);
      }
            catch (IOException e)
            {
        Log.debug("failed to retransmit response on timer G expiry", e);
      }
      gDelay = gDelay * 2;
      startTimer(TIMER_G, Math.min(gDelay, __T2));
      break;
    case TIMER_H:
      // TODO ? SipErrorListener.noAck
      cancelTimer(TIMER_G);
      terminate();
      break;
    case TIMER_I:
    case TIMER_J:
    case TIMER_L:
      terminate();
      break;
    default:
      throw new RuntimeException("unknown timeout id " + id);
    }
  }
 
  public void terminate()
    {
    _provisionalResponse = _finalResponse = null;
        setState(STATE_TERMINATED);
        getCallSession().removeServerTransaction(this);
       
        if (_listener != null) // TODO check
          _listener.transactionTerminated(this);
    }
 
  public String asString(int timer)
  {
    return "Timer" + TIMERS[timer];
  }
}
TOP

Related Classes of org.cipango.server.transaction.ServerTransaction

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.