org.restcomm.protocols.ss7.tcapAnsi.DialogImpl Maven / Gradle / Ivy
/*
* Mobius Software LTD
* Copyright 2019, Mobius Software LTD and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
*/
package org.restcomm.protocols.ss7.tcapAnsi;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.restcomm.protocols.ss7.sccp.parameter.SccpAddress;
import org.restcomm.protocols.ss7.tcapAnsi.api.TCAPException;
import org.restcomm.protocols.ss7.tcapAnsi.api.TCAPSendException;
import org.restcomm.protocols.ss7.tcapAnsi.api.TCAPStack;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.ApplicationContext;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.DialogPortion;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.ParseException;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.ProtocolVersion;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.UserInformation;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.Component;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.ComponentPortion;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.ComponentType;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.Invoke;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.PAbortCause;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.Reject;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.RejectProblem;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.Return;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.TCAbortMessage;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.TCConversationMessage;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.TCQueryMessage;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.TCResponseMessage;
import org.restcomm.protocols.ss7.tcapAnsi.api.asn.comp.TCUniMessage;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.component.InvokeClass;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.component.OperationState;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.Dialog;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.TRPseudoState;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCConversationIndication;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCConversationRequest;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCPAbortIndication;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCQueryIndication;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCQueryRequest;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCResponseIndication;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCResponseRequest;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCUniIndication;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCUniRequest;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCUserAbortIndication;
import org.restcomm.protocols.ss7.tcapAnsi.api.tc.dialog.events.TCUserAbortRequest;
import org.restcomm.protocols.ss7.tcapAnsi.asn.TcapFactory;
import org.restcomm.protocols.ss7.tcapAnsi.asn.Utils;
import com.mobius.software.telco.protocols.ss7.asn.ASNParser;
import io.netty.buffer.ByteBuf;
/**
* @author baranowb
* @author amit bhayani
* @author sergey vetyutnev
* @author yulianoifa
*
*/
public class DialogImpl implements Dialog {
private static final long serialVersionUID = 1L;
// timeout of remove task after TC_END
//private static final int _REMOVE_TIMEOUT = 30000;
private static final Logger logger = LogManager.getLogger(DialogImpl.class);
private Object userObject;
// values for timer timeouts
//private long removeTaskTimeout = _REMOVE_TIMEOUT;
private long idleTaskTimeout;
// sent/received acn, holds last acn/ui.
private ApplicationContext lastACN;
private UserInformation lastUI; // optional
private Long localTransactionIdObject;
private long localTransactionId;
private Long remoteTransactionIdObject;
private ProtocolVersion protocolVersion;
private SccpAddress localAddress;
private SccpAddress remoteAddress;
private int localSsn;
private AtomicReference> idleTimerFuture=new AtomicReference>();
private AtomicBoolean idleTimerActionTaken = new AtomicBoolean(false);
private AtomicBoolean idleTimerInvoked = new AtomicBoolean(false);
private AtomicReference state = new AtomicReference(TRPseudoState.Idle);
private boolean structured = true;
// invokde ID space :)
private static final boolean _INVOKEID_TAKEN = true;
private static final boolean _INVOKEID_FREE = false;
private static final int _INVOKE_TABLE_SHIFT = 128;
private boolean[] invokeIDTable = new boolean[256];
private int freeCount = invokeIDTable.length;
private int lastInvokeIdIndex = _INVOKE_TABLE_SHIFT - 1;
// only originating side keeps FSM, see: Q.771 - 3.1.5
protected Invoke[] operationsSent = new Invoke[invokeIDTable.length];
protected Invoke[] operationsSentA = new Invoke[invokeIDTable.length];
private ConcurrentHashMap incomingInvokeList = new ConcurrentHashMap();
private ScheduledExecutorService executor;
// scheduled components list
private List scheduledComponentList = new ArrayList();
private TCAPProviderImpl provider;
private int seqControl;
// If the Dialogue Portion is sent in TCBegin message, the first received
// Continue message should have the Dialogue Portion too
private boolean dpSentInBegin = false;
private int networkId;
private boolean isSwapTcapIdBytes;
private ASNParser dialogParser;
private static int getIndexFromInvokeId(Long l) {
int tmp = l.intValue();
return tmp + _INVOKE_TABLE_SHIFT;
}
private static Long getInvokeIdFromIndex(int index) {
int tmp = index - _INVOKE_TABLE_SHIFT;
return new Long(tmp);
}
/**
* Creating a Dialog for normal mode
*
* @param localAddress
* @param remoteAddress
* @param origTransactionId
* @param structured
* @param executor
* @param provider
* @param seqControl
* @param previewMode
*/
protected DialogImpl(SccpAddress localAddress, SccpAddress remoteAddress, Long origTransactionId, boolean structured,
ScheduledExecutorService executor, TCAPProviderImpl provider, int seqControl,ASNParser dialogParser) {
super();
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
if (origTransactionId != null) {
this.localTransactionIdObject = origTransactionId;
this.localTransactionId = origTransactionId;
}
this.executor = executor;
this.provider = provider;
this.structured = structured;
this.seqControl = seqControl;
TCAPStack stack = this.provider.getStack();
this.idleTaskTimeout = stack.getDialogIdleTimeout();
this.isSwapTcapIdBytes = stack.getSwapTcapIdBytes();
this.dialogParser=dialogParser;
// start
startIdleTimer();
}
public void release() {
for (int i = 0; i < this.operationsSent.length; i++) {
Invoke invokeImpl = this.operationsSent[i];
if (invokeImpl != null) {
invokeImpl.setState(OperationState.Idle);
// TODO whether to call operationTimedOut or not is still not clear
// operationTimedOut(invokeImpl);
}
}
this.setState(TRPseudoState.Expunged);
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#getDialogId()
*/
public Long getLocalDialogId() {
return localTransactionIdObject;
}
/**
*
*/
public Long getRemoteDialogId() {
return this.remoteTransactionIdObject;
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#getNewInvokeId()
*/
public Long getNewInvokeId() throws TCAPException {
if (this.freeCount == 0) {
throw new TCAPException("No free invokeId");
}
int tryCnt = 0;
while (true) {
if (++this.lastInvokeIdIndex >= this.invokeIDTable.length)
this.lastInvokeIdIndex = 0;
if (this.invokeIDTable[this.lastInvokeIdIndex] == _INVOKEID_FREE) {
freeCount--;
this.invokeIDTable[this.lastInvokeIdIndex] = _INVOKEID_TAKEN;
return getInvokeIdFromIndex(this.lastInvokeIdIndex);
}
if (++tryCnt >= 256)
throw new TCAPException("No free invokeId");
}
}
public int getNetworkId() {
return networkId;
}
public void setNetworkId(int networkId) {
this.networkId = networkId;
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#cancelInvocation (java.lang.Long)
*/
public boolean cancelInvocation(Long invokeId) throws TCAPException {
int index = getIndexFromInvokeId(invokeId);
if (index < 0 || index >= this.operationsSent.length) {
throw new TCAPException("Wrong invoke id passed.");
}
// lookup through send buffer.
for (index = 0; index < this.scheduledComponentList.size(); index++) {
Component cr = this.scheduledComponentList.get(index);
Long correlationID=null;
if (cr.getType() == ComponentType.InvokeNotLast || cr.getType() == ComponentType.InvokeLast)
correlationID=cr.getCorrelationId();
if(correlationID!=null && correlationID.equals(invokeId)) {
this.scheduledComponentList.remove(index);
((Invoke)cr).stopTimer();
((Invoke)cr).setState(OperationState.Idle);
return true;
}
}
return false;
}
private void freeInvokeId(Long l) {
int index = getIndexFromInvokeId(l);
if (this.invokeIDTable[index] == _INVOKEID_TAKEN)
this.freeCount++;
this.invokeIDTable[index] = _INVOKEID_FREE;
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#getRemoteAddress()
*/
public SccpAddress getRemoteAddress() {
return this.remoteAddress;
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#getLocalAddress()
*/
public SccpAddress getLocalAddress() {
return this.localAddress;
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#getSsn()
*/
@Override
public int getLocalSsn() {
return localSsn;
}
public void setLocalSsn(int newSsn) {
localSsn = newSsn;
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#isEstabilished()
*/
public boolean isEstabilished() {
return this.state.get() == TRPseudoState.Active;
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#isStructured()
*/
public boolean isStructured() {
return this.structured;
}
public void keepAlive() {
if (this.idleTimerInvoked.get()) {
this.idleTimerActionTaken.set(true);
}
}
/**
* @return the acn
*/
public ApplicationContext getApplicationContextName() {
return lastACN;
}
/**
* @return the ui
*/
public UserInformation getUserInformation() {
return lastUI;
}
/**
* Adding the new incoming invokeId into incomingInvokeList list
*
* @param invokeId
* @return false: failure - this invokeId already present in the list
*/
private boolean addIncomingInvokeId(Long invokeId) {
if(invokeId==null)
return false;
Long oldValue=this.incomingInvokeList.putIfAbsent(invokeId, invokeId);
return (oldValue==null);
}
private void removeIncomingInvokeId(Long invokeId) {
if(invokeId!=null)
this.incomingInvokeList.remove(invokeId);
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#send(org.restcomm
* .protocols.ss7.tcap.api.tc.dialog.events.TCBeginRequest)
*/
public void send(TCQueryRequest event) throws TCAPSendException {
if (this.state.get()!=TRPseudoState.Idle) {
throw new TCAPSendException("Can not send Begin in this state: " + this.state);
}
if (!this.isStructured()) {
throw new TCAPSendException("Unstructured dialogs do not use Begin");
}
this.idleTimerActionTaken.set(true);
restartIdleTimer();
TCQueryMessage tcbm = TcapFactory.createTCQueryMessage(event.getDialogTermitationPermission());
// build DP
tcbm.setOriginatingTransactionId(Utils.encodeTransactionId(this.localTransactionId, this.isSwapTcapIdBytes));
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
this.dpSentInBegin = true;
this.lastACN = event.getApplicationContext();
if (event.getUserInformation() != null) {
this.lastUI = event.getUserInformation();
}
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
if(event.getSecurityContext()!=null)
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
tcbm.setDialogPortion(dp);
}
// now comps
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
this.prepareComponents(componentsToSend);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
try {
ByteBuf buffer=dialogParser.encode(tcbm);
provider.getStack().newMessageSent(tcbm.getName(),buffer.readableBytes(), this.getNetworkId());
this.setState(TRPseudoState.InitialSent);
this.provider.send(buffer, event.getReturnMessageOnError(), this.remoteAddress, this.localAddress,
this.seqControl, this.getNetworkId(), this.localSsn);
this.scheduledComponentList.clear();
} catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error("Failed to send message: ", e);
}
throw new TCAPSendException("Failed to send TC-Query message: " + e.getMessage(), e);
}
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#send(org.restcomm
* .protocols.ss7.tcap.api.tc.dialog.events.TCContinueRequest)
*/
public void send(TCConversationRequest event) throws TCAPSendException {
if (!this.isStructured()) {
throw new TCAPSendException("Unstructured dialogs do not use Continue");
}
if (this.state.get() == TRPseudoState.InitialReceived) {
this.idleTimerActionTaken.set(true);
restartIdleTimer();
TCConversationMessage tcbm = TcapFactory.createTCConversationMessage(event.getDialogTermitationPermission());
tcbm.setOriginatingTransactionId(Utils.encodeTransactionId(this.localTransactionId, this.isSwapTcapIdBytes));
tcbm.setDestinationTransactionId(Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes));
// local address may change, lets check it;
if (event.getOriginatingAddress() != null && !event.getOriginatingAddress().equals(this.localAddress)) {
this.localAddress = event.getOriginatingAddress();
}
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
// set dialog portion
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
tcbm.setDialogPortion(dp);
}
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
this.prepareComponents(componentsToSend);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
try {
ByteBuf buffer=dialogParser.encode(tcbm);
provider.getStack().newMessageSent(tcbm.getName(),buffer.readableBytes(), this.getNetworkId());
this.provider.send(buffer, event.getReturnMessageOnError(), this.remoteAddress,
this.localAddress, this.seqControl, this.getNetworkId(), this.localSsn);
this.setState(TRPseudoState.Active);
this.scheduledComponentList.clear();
} catch (Exception e) {
// FIXME: remove freshly added invokes to free invoke ID??
if (logger.isErrorEnabled()) {
logger.error("Failed to send message: ", e);
}
throw new TCAPSendException("Failed to send TC-Continue message: " + e.getMessage(), e);
}
} else if (state.get() == TRPseudoState.Active) {
this.idleTimerActionTaken.set(true);
restartIdleTimer();
// in this we ignore acn and passed args(except qos)
TCConversationMessage tcbm = TcapFactory.createTCConversationMessage(event.getDialogTermitationPermission());
tcbm.setOriginatingTransactionId(Utils.encodeTransactionId(this.localTransactionId, this.isSwapTcapIdBytes));
tcbm.setDestinationTransactionId(Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes));
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
this.prepareComponents(componentsToSend);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
try {
ByteBuf buffer=dialogParser.encode(tcbm);
provider.getStack().newMessageSent(tcbm.getName(),buffer.readableBytes(), this.getNetworkId());
this.provider.send(buffer, event.getReturnMessageOnError(), this.remoteAddress,
this.localAddress, this.seqControl, this.getNetworkId(), this.localSsn);
this.scheduledComponentList.clear();
} catch (Exception e) {
// FIXME: remove freshly added invokes to free invoke ID??
if (logger.isErrorEnabled()) {
logger.error("Failed to send message: ", e);
}
throw new TCAPSendException("Failed to send TC-Continue message: " + e.getMessage(), e);
}
} else {
throw new TCAPSendException("Wrong state: " + this.state);
}
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#send(org.restcomm
* .protocols.ss7.tcap.api.tc.dialog.events.TCEndRequest)
*/
public void send(TCResponseRequest event) throws TCAPSendException {
if (!this.isStructured()) {
throw new TCAPSendException("Unstructured dialogs do not use Response");
}
TCResponseMessage tcbm = null;
if (state.get() == TRPseudoState.InitialReceived) {
// TC-END request primitive issued in response to a TC-BEGIN
// indication primitive
this.idleTimerActionTaken.set(true);
stopIdleTimer();
tcbm = TcapFactory.createTCResponseMessage();
tcbm.setDestinationTransactionId(Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes));
// local address may change, lets check it;
if (event.getOriginatingAddress() != null && !event.getOriginatingAddress().equals(this.localAddress)) {
this.localAddress = event.getOriginatingAddress();
}
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
// set dialog portion
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
tcbm.setDialogPortion(dp);
}
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
this.prepareComponents(componentsToSend);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
} else if (state.get() == TRPseudoState.Active) {
restartIdleTimer();
tcbm = TcapFactory.createTCResponseMessage();
tcbm.setDestinationTransactionId(Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes));
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
this.prepareComponents(componentsToSend);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
} else {
throw new TCAPSendException(String.format("State is not %s or %s: it is %s", TRPseudoState.Active,
TRPseudoState.InitialReceived, this.state));
}
try {
ByteBuf buffer=dialogParser.encode(tcbm);
provider.getStack().newMessageSent(tcbm.getName(),buffer.readableBytes(), this.getNetworkId());
this.provider.send(buffer, event.getReturnMessageOnError(), this.remoteAddress, this.localAddress,
this.seqControl, this.getNetworkId(), this.localSsn);
this.scheduledComponentList.clear();
} catch (Exception e) {
// FIXME: remove freshly added invokes to free invoke ID??
if (logger.isErrorEnabled()) {
logger.error("Failed to send message: ", e);
}
throw new TCAPSendException("Failed to send TC-Response message: " + e.getMessage(), e);
} finally {
// FIXME: is this proper place - should we not release in case
// of error ?
release();
}
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#sendUni()
*/
public void send(TCUniRequest event) throws TCAPSendException {
if (this.isStructured()) {
throw new TCAPSendException("Structured dialogs do not use Uni");
}
TCUniMessage msg = TcapFactory.createTCUniMessage();
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
// set dialog portion
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
msg.setDialogPortion(dp);
}
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
this.prepareComponents(componentsToSend);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
msg.setComponent(cPortion);
}
try {
ByteBuf buffer=dialogParser.encode(msg);
provider.getStack().newMessageSent(msg.getName(),buffer.readableBytes(), this.getNetworkId());
this.provider.send(buffer, event.getReturnMessageOnError(), this.remoteAddress, this.localAddress,
this.seqControl, this.getNetworkId(), this.localSsn);
this.scheduledComponentList.clear();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("Failed to send message: ", e);
}
throw new TCAPSendException("Failed to send TC-Uni message: " + e.getMessage(), e);
} finally {
release();
}
}
public void send(TCUserAbortRequest event) throws TCAPSendException {
// is abort allowed in "Active" state ?
if (!isStructured()) {
throw new TCAPSendException("Unstructured dialog can not be aborted!");
}
if (this.state.get() == TRPseudoState.InitialReceived || this.state.get() == TRPseudoState.Active) {
TCAbortMessage msg = TcapFactory.createTCAbortMessage();
msg.setDestinationTransactionId(Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes));
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
// set dialog portion
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
msg.setDialogPortion(dp);
}
msg.setUserAbortInformation(event.getUserAbortInformation());
if (state.get() == TRPseudoState.InitialReceived) {
// local address may change, lets check it
if (event.getOriginatingAddress() != null && !event.getOriginatingAddress().equals(this.localAddress)) {
this.localAddress = event.getOriginatingAddress();
}
}
try {
ByteBuf buffer=dialogParser.encode(msg);
if(msg.getPAbortCause()!=null)
provider.getStack().newAbortSent(msg.getPAbortCause().name(), this.getNetworkId());
else
provider.getStack().newAbortSent("User", this.getNetworkId());
provider.getStack().newMessageSent(msg.getName(),buffer.readableBytes(), this.getNetworkId());
this.provider.send(buffer, event.getReturnMessageOnError(), this.remoteAddress,
this.localAddress, this.seqControl, this.getNetworkId(), this.localSsn);
this.scheduledComponentList.clear();
} catch (Exception e) {
// FIXME: remove freshly added invokes to free invoke ID??
if (logger.isErrorEnabled()) {
e.printStackTrace();
logger.error("Failed to send message: ", e);
}
throw new TCAPSendException("Failed to send TC-U-Abort message: " + e.getMessage(), e);
} finally {
release();
}
} else if (this.state.get() == TRPseudoState.InitialSent) {
release();
}
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#sendComponent(org
* .restcomm.protocols.ss7.tcap.api.tc.component.ComponentRequest)
*/
public void sendComponent(Component componentRequest) throws TCAPSendException {
if (componentRequest.getType() == ComponentType.InvokeLast || componentRequest.getType() == ComponentType.InvokeNotLast) {
// check if its taken!
int invokeIndex = getIndexFromInvokeId(((Invoke)componentRequest).getInvokeId());
if (this.operationsSent[invokeIndex] != null) {
throw new TCAPSendException("There is already operation with such invoke id!");
}
((Invoke)componentRequest).setState(OperationState.Pending);
((Invoke)componentRequest).setDialog(this);
// if the Invoke timeout value has not be reset by TCAP-User
// for this invocation we are setting it to t((Invoke)componentRequest)he the TCAP stack
// default value
if (((Invoke)componentRequest).getTimeout() == TCAPStackImpl._EMPTY_INVOKE_TIMEOUT)
((Invoke)componentRequest).setTimeout(this.provider.getStack().getInvokeTimeout());
} else if (componentRequest.getType() != ComponentType.ReturnResultNotLast && componentRequest.getType() != ComponentType.ReturnResultLast) {
// we are sending a response and removing invokeId from
// incomingInvokeList
this.removeIncomingInvokeId(componentRequest.getCorrelationId());
}
this.scheduledComponentList.add(componentRequest);
}
public void processInvokeWithoutAnswer(Long invokeId) {
this.removeIncomingInvokeId(invokeId);
}
private void prepareComponents(List res) {
int index = 0;
while (this.scheduledComponentList.size() > index) {
Component cr = this.scheduledComponentList.get(index);
if(cr.getType()!=null && cr.getType().name()!=null)
provider.getStack().newComponentSent(cr.getType().name(), this.getNetworkId());
if (cr.getType() == ComponentType.InvokeNotLast || cr.getType() == ComponentType.InvokeLast) {
Invoke in = (Invoke)cr;
// FIXME: check not null?
this.operationsSent[getIndexFromInvokeId(in.getInvokeId())] = in;
in.setState(OperationState.Sent);
}
else if(cr.getType()==ComponentType.Reject) {
Reject reject=(Reject)cr;
try {
if(reject.getProblem()!=null) {
provider.getStack().newRejectSent(reject.getProblem().name(), this.getNetworkId());
}
}
catch(ParseException ex) {
}
}
res.add(cr);
index++;
}
}
public int getMaxUserDataLength() {
return this.provider.getMaxUserDataLength(remoteAddress, localAddress, this.networkId);
}
public int getDataLength(TCQueryRequest event) throws TCAPSendException {
TCQueryMessage tcbm = TcapFactory.createTCQueryMessage(event.getDialogTermitationPermission());
tcbm.setOriginatingTransactionId(Utils.encodeTransactionId(this.localTransactionId, this.isSwapTcapIdBytes));
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
tcbm.setDialogPortion(dp);
}
// now comps
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
componentsToSend.addAll(this.scheduledComponentList);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
try {
ByteBuf buffer=dialogParser.encode(tcbm);
return buffer.readableBytes();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("Failed to encode message while length testing: ", e);
}
throw new TCAPSendException("Error encoding TCBeginRequest", e);
}
}
public int getDataLength(TCConversationRequest event) throws TCAPSendException {
TCConversationMessage tcbm = TcapFactory.createTCConversationMessage(event.getDialogTermitationPermission());
tcbm.setOriginatingTransactionId(Utils.encodeTransactionId(this.localTransactionId, this.isSwapTcapIdBytes));
tcbm.setDestinationTransactionId(Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes));
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
// set dialog portion
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
tcbm.setDialogPortion(dp);
}
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
componentsToSend.addAll(this.scheduledComponentList);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
try {
ByteBuf buffer=dialogParser.encode(tcbm);
return buffer.readableBytes();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("Failed to encode message while length testing: ", e);
}
throw new TCAPSendException("Error encoding TCContinueRequest", e);
}
}
public int getDataLength(TCResponseRequest event) throws TCAPSendException {
// TC-END request primitive issued in response to a TC-BEGIN
// indication primitive
TCResponseMessage tcbm = TcapFactory.createTCResponseMessage();
tcbm.setDestinationTransactionId(Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes));
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
componentsToSend.addAll(this.scheduledComponentList);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
tcbm.setComponent(cPortion);
}
if (state.get() == TRPseudoState.InitialReceived) {
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
// set dialog portion
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
tcbm.setDialogPortion(dp);
}
}
try {
ByteBuf buffer=dialogParser.encode(tcbm);
return buffer.readableBytes();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("Failed to encode message while length testing: ", e);
}
throw new TCAPSendException("Error encoding TCEndRequest", e);
}
}
public int getDataLength(TCUniRequest event) throws TCAPSendException {
TCUniMessage msg = TcapFactory.createTCUniMessage();
if (event.getApplicationContext() != null || event.getConfidentiality() != null
|| event.getSecurityContext() != null || event.getUserInformation() != null) {
// set dialog portion
DialogPortion dp = TcapFactory.createDialogPortion();
dp.setProtocolVersion(TcapFactory.createProtocolVersionFull());
dp.setApplicationContext(event.getApplicationContext());
dp.setUserInformation(event.getUserInformation());
dp.setSecurityContext(event.getSecurityContext());
dp.setConfidentiality(event.getConfidentiality());
msg.setDialogPortion(dp);
}
if (this.scheduledComponentList.size() > 0) {
List componentsToSend = new ArrayList(this.scheduledComponentList.size());
componentsToSend.addAll(this.scheduledComponentList);
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(componentsToSend);
msg.setComponent(cPortion);
}
try {
ByteBuf buffer=dialogParser.encode(msg);
return buffer.readableBytes();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("Failed to encode message while length testing: ", e);
}
throw new TCAPSendException("Error encoding TCUniRequest", e);
}
}
// /////////////////
// LOCAL METHODS //
// /////////////////
@Override
public ProtocolVersion getProtocolVersion() {
return protocolVersion;
}
@Override
public void setProtocolVersion(ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion;
}
/**
* @param remoteTransactionId the remoteTransactionId to set
*/
void setRemoteTransactionId(ByteBuf remoteTransactionId) {
if(remoteTransactionId!=null)
this.remoteTransactionIdObject = Utils.decodeTransactionId(remoteTransactionId, this.isSwapTcapIdBytes);
}
/**
* @param localAddress the localAddress to set
*/
public void setLocalAddress(SccpAddress localAddress) {
this.localAddress = localAddress;
}
/**
* @param remoteAddress the remoteAddress to set
*/
public void setRemoteAddress(SccpAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
void processUni(TCUniMessage msg, SccpAddress localAddress, SccpAddress remoteAddress) {
// TCUniIndicationImpl tcUniIndication = null;
try {
this.setRemoteAddress(remoteAddress);
this.setLocalAddress(localAddress);
// no dialog portion!
// convert to indications
TCUniIndication tcUniIndication = this.provider.getDialogPrimitiveFactory().createUniIndication(this);
tcUniIndication.setDestinationAddress(localAddress);
tcUniIndication.setOriginatingAddress(remoteAddress);
// now comps
ComponentPortion comps = msg.getComponent();
tcUniIndication.setComponents(comps);
if (msg.getDialogPortion() != null) {
DialogPortion dp = msg.getDialogPortion();
this.lastACN = dp.getApplicationContext();
this.lastUI = dp.getUserInformation();
tcUniIndication.setApplicationContext(this.lastACN);
tcUniIndication.setUserInformation(this.lastUI);
tcUniIndication.setConfidentiality(msg.getDialogPortion().getConfidentiality());
tcUniIndication.setSecurityContext(msg.getDialogPortion().getSecurityContext());
}
// lets deliver to provider, this MUST not throw anything
this.provider.deliver(this, tcUniIndication);
} finally {
this.release();
}
}
protected void processQuery(TCQueryMessage msg, SccpAddress localAddress, SccpAddress remoteAddress,
boolean dialogTermitationPermission) {
TCQueryIndication tcBeginIndication = null;
// this is invoked ONLY for server.
if (state.get() != TRPseudoState.Idle) {
// should we terminate dialog here?
if (logger.isErrorEnabled()) {
logger.error("Received Begin primitive, but state is not: " + TRPseudoState.Idle + ". Dialog: " + this);
}
this.sendAbnormalDialog();
return;
}
restartIdleTimer();
// lets setup
this.setRemoteAddress(remoteAddress);
this.setLocalAddress(localAddress);
this.setRemoteTransactionId(msg.getOriginatingTransactionId());
// convert to indications
tcBeginIndication = this.provider.getDialogPrimitiveFactory().createQueryIndication(this, dialogTermitationPermission);
tcBeginIndication.setDestinationAddress(localAddress);
tcBeginIndication.setOriginatingAddress(remoteAddress);
// if APDU and context data present, lets store it
DialogPortion dialogPortion = msg.getDialogPortion();
if (dialogPortion != null) {
this.lastACN = dialogPortion.getApplicationContext();
this.lastUI = dialogPortion.getUserInformation();
tcBeginIndication.setApplicationContext(this.lastACN);
tcBeginIndication.setUserInformation(this.lastUI);
tcBeginIndication.setConfidentiality(msg.getDialogPortion().getConfidentiality());
tcBeginIndication.setSecurityContext(msg.getDialogPortion().getSecurityContext());
}
ComponentPortion cPortion=TcapFactory.createComponentPortion();
if(msg.getComponent()!=null)
cPortion.setComponents(processOperationsState(msg.getComponent().getComponents()));
tcBeginIndication.setComponents(cPortion);
// change state - before we deliver
this.setState(TRPseudoState.InitialReceived);
// lets deliver to provider
this.provider.deliver(this, tcBeginIndication);
}
protected void processConversation(TCConversationMessage msg, SccpAddress localAddress, SccpAddress remoteAddressm,
boolean dialogTermitationPermission) {
TCConversationIndication tcContinueIndication = null;
if (state.get() == TRPseudoState.InitialSent) {
restartIdleTimer();
tcContinueIndication = this.provider.getDialogPrimitiveFactory().createConversationIndication(this, dialogTermitationPermission);
// in continue remote address MAY change be changed, so lets
// update!
this.setRemoteAddress(remoteAddress);
this.setRemoteTransactionId(msg.getOriginatingTransactionId());
tcContinueIndication.setOriginatingAddress(remoteAddress);
// here we will receive DialogResponse APDU - if request was
// present!
DialogPortion dialogPortion = msg.getDialogPortion();
if (dialogPortion != null) {
this.lastACN = dialogPortion.getApplicationContext();
this.lastUI = dialogPortion.getUserInformation();
tcContinueIndication.setApplicationContext(this.lastACN);
tcContinueIndication.setUserInformation(this.lastUI);
tcContinueIndication.setConfidentiality(msg.getDialogPortion().getConfidentiality());
tcContinueIndication.setSecurityContext(msg.getDialogPortion().getSecurityContext());
} else if (this.dpSentInBegin) {
sendAbnormalDialog();
return;
}
tcContinueIndication.setOriginatingAddress(remoteAddress);
// now comps
ComponentPortion cPortion=TcapFactory.createComponentPortion();
cPortion.setComponents(processOperationsState(msg.getComponent().getComponents()));
tcContinueIndication.setComponents(cPortion);
// change state
this.setState(TRPseudoState.Active);
// lets deliver to provider
this.provider.deliver(this, tcContinueIndication);
} else if (state.get() == TRPseudoState.Active) {
restartIdleTimer();
// XXX: here NO APDU will be present, hence, no ACN/UI change
tcContinueIndication = this.provider.getDialogPrimitiveFactory().createConversationIndication(this, dialogTermitationPermission);
tcContinueIndication.setOriginatingAddress(remoteAddress);
// now comps
ComponentPortion cPortion=TcapFactory.createComponentPortion();
if(msg.getComponent()!=null)
cPortion.setComponents(processOperationsState(msg.getComponent().getComponents()));
tcContinueIndication.setComponents(cPortion);
// lets deliver to provider
this.provider.deliver(this, tcContinueIndication);
} else {
if (logger.isErrorEnabled()) {
logger.error(
"Received Continue primitive, but state is not proper: " + this.state + ", Dialog: " + this);
}
this.sendAbnormalDialog();
return;
}
}
protected void processResponse(TCResponseMessage msg, SccpAddress localAddress, SccpAddress remoteAddress) {
TCResponseIndication tcResponseIndication = null;
try {
restartIdleTimer();
tcResponseIndication = this.provider.getDialogPrimitiveFactory().createResponseIndication(this);
if (state.get() == TRPseudoState.InitialSent) {
// in end remote address MAY change be changed, so lets
// update!
this.setRemoteAddress(remoteAddress);
tcResponseIndication.setOriginatingAddress(remoteAddress);
}
DialogPortion dialogPortion = msg.getDialogPortion();
if (dialogPortion != null) {
this.lastACN = dialogPortion.getApplicationContext();
this.lastUI = dialogPortion.getUserInformation();
tcResponseIndication.setApplicationContext(this.lastACN);
tcResponseIndication.setUserInformation(this.lastUI);
tcResponseIndication.setConfidentiality(msg.getDialogPortion().getConfidentiality());
tcResponseIndication.setSecurityContext(msg.getDialogPortion().getSecurityContext());
}
// now comps
ComponentPortion cPortion=TcapFactory.createComponentPortion();
if(msg.getComponent()!=null)
cPortion.setComponents(processOperationsState(msg.getComponent().getComponents()));
tcResponseIndication.setComponents(cPortion);
this.provider.deliver(this, tcResponseIndication);
} finally {
release();
}
}
protected void processAbort(TCAbortMessage msg, SccpAddress localAddress2, SccpAddress remoteAddress2) {
try {
PAbortCause type = null;
try {
type = msg.getPAbortCause();
} catch(ParseException ex) {
}
if (type != null) {
// its TC-P-Abort
TCPAbortIndication tcAbortIndication = this.provider.getDialogPrimitiveFactory().createPAbortIndication(this);
tcAbortIndication.setPAbortCause(type);
this.provider.deliver(this, tcAbortIndication);
} else {
// its TC-U-Abort
TCUserAbortIndication tcUAbortIndication = this.provider.getDialogPrimitiveFactory().createUAbortIndication(this);
DialogPortion dp = msg.getDialogPortion();
if (dp != null) {
tcUAbortIndication.setApplicationContextName(dp.getApplicationContext());
tcUAbortIndication.setUserInformation(dp.getUserInformation());
tcUAbortIndication.setSecurityContext(dp.getSecurityContext());
tcUAbortIndication.setConfidentiality(dp.getConfidentiality());
}
tcUAbortIndication.setUserAbortInformation(msg.getUserAbortInformation());
if (state.get() == TRPseudoState.InitialSent) {
// in userAbort remote address MAY change be changed, so lets
// update!
this.setRemoteAddress(remoteAddress);
tcUAbortIndication.setOriginatingAddress(remoteAddress);
}
this.provider.deliver(this, tcUAbortIndication);
}
} finally {
release();
}
}
protected void sendAbnormalDialog() {
TCPAbortIndication tcAbortIndication = null;
try {
if (this.remoteTransactionIdObject == null) {
// no remoteTransactionId - we can not send back TC-ABORT
return;
}
// sending to the remote side
if (this.getProtocolVersion() != null) {
this.provider.sendProviderAbort(PAbortCause.InconsistentDialoguePortion, Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes), remoteAddress,
localAddress, seqControl, this.getNetworkId());
} else {
this.provider.sendRejectAsProviderAbort(PAbortCause.InconsistentDialoguePortion, Utils.encodeTransactionId(this.remoteTransactionIdObject, this.isSwapTcapIdBytes),
remoteAddress, localAddress, seqControl, this.getNetworkId());
}
// sending to the local side
tcAbortIndication = this.provider.getDialogPrimitiveFactory().createPAbortIndication(this);
tcAbortIndication.setPAbortCause(PAbortCause.InconsistentDialoguePortion);
this.provider.deliver(this, tcAbortIndication);
} finally {
this.release();
}
}
public Invoke getInvoke(Long correlationId) {
Invoke invoke = null;
int index = 0;
if (correlationId != null) {
index = getIndexFromInvokeId(correlationId);
invoke = this.operationsSent[index];
}
return invoke;
}
protected List processOperationsState(List components) {
if (components == null) {
return null;
}
List resultingIndications = new ArrayList();
for (Component ci : components) {
Long invokeId;
invokeId = ci.getCorrelationId();
Invoke invoke = null;
int index = 0;
if (invokeId != null) {
index = getIndexFromInvokeId(invokeId);
invoke = this.operationsSent[index];
}
provider.getStack().newComponentReceived(ci.getType().name(), this.getNetworkId());
switch (ci.getType()) {
case InvokeNotLast:
case InvokeLast:
if (invokeId != null && invoke == null) {
logger.error(String.format("Rx : %s but no sent Invoke for correlationId exists", ci));
this.addReject(resultingIndications, ((Invoke)ci).getInvokeId(),
RejectProblem.invokeUnrecognisedCorrelationId);
} else {
if (invoke != null) {
((Invoke)ci).setCorrelationInvoke(invoke);
}
if (!this.addIncomingInvokeId(((Invoke)ci).getInvokeId())) {
logger.error(String.format("Rx : %s but there is already Invoke with this invokeId", ci));
this.addReject(resultingIndications, ((Invoke)ci).getInvokeId(),
RejectProblem.invokeDuplicateInvocation);
} else {
resultingIndications.add(ci);
}
}
break;
case ReturnResultNotLast:
if (invoke == null) {
logger.error(String.format("Rx : %s but there is no corresponding Invoke", ci));
this.addReject(resultingIndications, ci.getCorrelationId(),
RejectProblem.returnResultUnrecognisedCorrelationId);
} else if (invoke.getInvokeClass() != InvokeClass.Class1 && invoke.getInvokeClass() != InvokeClass.Class3) {
logger.error(String.format("Rx : %s but Invoke class is not 1 or 3", ci));
this.addReject(resultingIndications, ci.getCorrelationId(),
RejectProblem.returnResultUnexpectedReturnResult);
} else {
resultingIndications.add(ci);
Return rri = (Return)ci;
if (rri.getOperationCode() == null)
rri.setOperationCode(invoke.getOperationCode());
}
break;
case ReturnResultLast:
if (invoke == null) {
logger.error(String.format("Rx : %s but there is no corresponding Invoke", ci));
this.addReject(resultingIndications, ci.getCorrelationId(),
RejectProblem.returnResultUnrecognisedCorrelationId);
} else if (invoke.getInvokeClass() != InvokeClass.Class1 && invoke.getInvokeClass() != InvokeClass.Class3) {
logger.error(String.format("Rx : %s but Invoke class is not 1 or 3", ci));
this.addReject(resultingIndications, ci.getCorrelationId(),
RejectProblem.returnResultUnexpectedReturnResult);
} else {
invoke.onReturnResultLast();
if (invoke.isSuccessReported()) {
resultingIndications.add(ci);
}
Return rri = ((Return)ci);
if (rri.getOperationCode() == null)
rri.setOperationCode(invoke.getOperationCode());
}
break;
case ReturnError:
if (invoke == null) {
logger.error(String.format("Rx : %s but there is no corresponding Invoke", ci));
this.addReject(resultingIndications, ci.getCorrelationId(),
RejectProblem.returnErrorUnrecognisedCorrelationId);
} else if (invoke.getInvokeClass() != InvokeClass.Class1 && invoke.getInvokeClass() != InvokeClass.Class2) {
logger.error(String.format("Rx : %s but Invoke class is not 1 or 2", ci));
this.addReject(resultingIndications, ci.getCorrelationId(), RejectProblem.returnErrorUnexpectedError);
} else {
invoke.onError();
if (invoke.isErrorReported()) {
resultingIndications.add(ci);
}
}
break;
case Reject:
Reject rej = (Reject)ci;
RejectProblem problem = null;
try {
problem=rej.getProblem();
}
catch(ParseException ex) {
}
if(problem!=null)
provider.getStack().newRejectReceived(problem.name(), this.getNetworkId());
if (invoke != null) {
// If the Reject Problem is the InvokeProblemType we
// should move the invoke to the idle state
if (rej!=null && !rej.isLocalOriginated() && (problem == RejectProblem.invokeDuplicateInvocation
|| problem == RejectProblem.invokeIncorrectParameter
|| problem == RejectProblem.invokeUnrecognisedCorrelationId
|| problem == RejectProblem.invokeUnrecognisedOperation))
invoke.onReject();
}
if (rej.isLocalOriginated() && this.isStructured()) {
try {
// this is a local originated Reject - we are rejecting
// an incoming component
// we need to send a Reject also to a peer
this.sendComponent(ci);
} catch (TCAPSendException e) {
logger.error("TCAPSendException when sending Reject component : Dialog: " + this, e);
}
}
resultingIndications.add(ci);
break;
default:
resultingIndications.add(ci);
break;
}
}
return resultingIndications;
}
private void addReject(List resultingIndications, Long invokeId, RejectProblem p) {
try {
Reject rej = TcapFactory.createComponentReject();
rej.setLocalOriginated(true);
if(invokeId!=null)
rej.setCorrelationId(invokeId);
rej.setProblem(p);
resultingIndications.add(rej);
if (this.isStructured())
this.sendComponent(rej);
} catch (TCAPSendException e) {
logger.error(String.format("Error sending Reject component", e));
}
}
protected void setState(TRPseudoState newState) {
if(this.state.get()==TRPseudoState.Expunged)
return;
if(this.state.getAndSet(newState)==TRPseudoState.Expunged)
this.state.set(TRPseudoState.Expunged);
if (newState == TRPseudoState.Expunged) {
stopIdleTimer();
provider.release(this);
}
}
private void startIdleTimer() {
if (!this.structured)
return;
IdleTimerTask t = new IdleTimerTask();
t.d = this;
FutureTask dummyTask=new FutureTask(t,null);
if (!this.idleTimerFuture.compareAndSet(null, dummyTask)) {
throw new IllegalStateException();
}
this.idleTimerFuture.set(this.executor.schedule(t, this.idleTaskTimeout, TimeUnit.MILLISECONDS));
}
private void stopIdleTimer() {
if (!this.structured)
return;
Future> original=this.idleTimerFuture.getAndSet(null);
if (original != null) {
original.cancel(false);
}
}
private void restartIdleTimer() {
stopIdleTimer();
startIdleTimer();
}
private class IdleTimerTask implements Runnable {
DialogImpl d;
public void run() {
d.idleTimerFuture.set(null);
d.idleTimerActionTaken.set(false);
d.idleTimerInvoked.set(true);
provider.timeout(d);
// send abort
if (d.idleTimerActionTaken.get()) {
startIdleTimer();
} else {
if (remoteTransactionIdObject != null && !getState().equals(TRPseudoState.Expunged)) {
sendAbnormalDialog();
}
else
release();
}
d.idleTimerInvoked.set(false);
}
}
// ////////////////////
// IND like methods //
// ///////////////////
public void operationEnded(Invoke tcInvokeRequestImpl) {
// this op died cause of timeout, TC-L-CANCEL!
int index = getIndexFromInvokeId(tcInvokeRequestImpl.getInvokeId());
freeInvokeId(tcInvokeRequestImpl.getInvokeId());
this.operationsSent[index] = null;
// lets call listener
// This is done actually with COmponentIndication ....
}
/*
* (non-Javadoc)
*
* @see org.restcomm.protocols.ss7.tcap.api.tc.dialog.Dialog#operationEnded(
* org.restcomm.protocols.ss7.tcap.tc.component.TCInvokeRequestImpl)
*/
public void operationTimedOut(Invoke invoke) {
// this op died cause of timeout, TC-L-CANCEL!
int index = getIndexFromInvokeId(invoke.getInvokeId());
freeInvokeId(invoke.getInvokeId());
this.operationsSent[index] = null;
// lets call listener
this.provider.operationTimedOut(invoke,networkId);
}
// TC-TIMER-RESET
public void resetTimer(Long invokeId) throws TCAPException {
int index = getIndexFromInvokeId(invokeId);
Invoke invoke = operationsSent[index];
if (invoke == null) {
throw new TCAPException("No operation with this ID");
}
invoke.startTimer();
}
public TRPseudoState getState() {
return this.state.get();
}
public Object getUserObject() {
return this.userObject;
}
public void setUserObject(Object userObject) {
this.userObject = userObject;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return super.toString() + ": Local[" + this.getLocalDialogId() + "] Remote[" + this.getRemoteDialogId()
+ "], LocalAddress[" + localAddress + "] RemoteAddress[" + this.remoteAddress + "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy