Fields Summary |
---|
protected static final int | BASE_TIMER_INTERVALTransaction timer interval. |
protected static final int | T1RTT Estimate. 500ms default. |
protected static final int | T45 sec Maximum duration a message will remain in the network |
protected static final int | T2The maximum retransmit interval for non-INVITE
requests and INVITE responses |
protected static final int | TIMER_AINVITE request retransmit interval, for UDP only |
protected static final int | TIMER_BINVITE transaction timeout timer |
protected static final int | TIMER_JINVITE transaction timeout timer |
protected static final int | TIMER_FINVITE transaction timeout timer |
protected static final int | TIMER_HINVITE transaction timeout timer |
protected static final int | TIMER_IINVITE transaction timeout timer |
protected static final int | TIMER_KINVITE transaction timeout timer |
protected static final int | TIMER_DINVITE transaction timeout timer |
protected static final int | TIMER_CINVITE transaction timeout timer |
protected Response | lastResponseLast response message. |
protected Dialog | dialogCurrent SIP dialog. |
protected boolean | ackSeenFlagFlag indicating an ACK was received. |
protected boolean | toListenerFlag indicating listener waiting. |
public static final int | INITIAL_STATEInitialized but no state assigned. |
public static final int | TRYING_STATETrying state. |
public static final int | CALLING_STATECALLING State. |
public static final int | PROCEEDING_STATEProceeding state. |
public static final int | COMPLETED_STATECompleted state. |
public static final int | CONFIRMED_STATEConfirmed state. |
public static final int | TERMINATED_STATETerminated state. |
protected static final int | MAXIMUM_RETRANSMISSION_TICK_COUNTMaximum number of ticks between retransmissions. |
protected SIPTransactionStack | parentStackParent stack for this transaction. |
private Request | originalRequestOriginal request that is being handled by this transaction. |
protected MessageChannel | encapsulatedChannelUnderlying channel being used to send messages for this
transaction. |
private String | branchTransaction branch ID. |
private int | currentStateCurrent transaction state. |
private int | retransmissionTimerLastTickCountNumber of ticks the retransmission timer was set to last. |
private int | retransmissionTimerTicksLeftNumber of ticks before the message is retransmitted. |
private int | timeoutTimerTicksLeftNumber of ticks before the transaction times out. |
private Vector | eventListenersList of event listeners for this transaction. |
protected boolean | isCancelledFlag to indcate that this has been cancelled. |
protected Object | applicationDataObject representing the connection being held by the JSR180
Implementation It can be either a SipClientConnection in case
of a ClientTransaction or a SipConnectionNotifier in case of a
ServerTransaction. |
Methods Summary |
---|
protected boolean | IsServerTransaction()A shortcut way of telling if we are a server transaction.
return this instanceof ServerTransaction;
|
public void | addEventListener(SIPTransactionEventListener newListener)Adds a new event listener to this transaction.
eventListeners.addElement(newListener);
|
protected void | buildRouteSet(Request request)Create route set for request.
Message origMsg = lastResponse;
boolean isServer = false;
Dialog dlg = getDialog();
if (dlg != null) { // inside of dialog
Transaction firstTransaction = dlg.getFirstTransaction();
if (dlg.isServer()) { // dialog was created on server side
origMsg = firstTransaction.getOriginalRequest();
isServer = true;
} else { // dialog was created on client side
origMsg = firstTransaction.getLastResponse();
}
} else { // out of dialog
// IMPL_NOTE: implement a support for the case when Contact
// header is not present.
if (this instanceof ServerTransaction) {
origMsg = getOriginalRequest();
isServer = true;
}
}
if (origMsg == null) {
// Avoid NPE in case when sending ACK from the part that
// initiated a Re-INVITE.
return;
}
RecordRouteList recordRouteList = origMsg.getRecordRouteHeaders();
ContactList cl = origMsg.getContactHeaders();
if (cl == null) {
// Prevent NPE and log an error: Contact header is absent.
if (Logging.REPORT_LEVEL <= Logging.ERROR) {
Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
"Transaction.buildRouteSet(): Contact must be present!");
}
return;
}
ContactHeader contact = (ContactHeader)cl.getFirst();
if (recordRouteList == null) {
URI remoteTarget = contact.getAddress().getURI();
// RFC 3261, 12.2.1.1 Generating the Request
// If the route set is empty, the UAC MUST place the remote
// target URI into the Request-URI. The UAC MUST NOT add
// a Route header field to the request.
request.setRequestURI(remoteTarget);
} else {
request.removeHeader(Header.ROUTE);
RouteList routeList = new RouteList();
// start at the end of the list and walk backwards
Vector li = recordRouteList.getHeaders();
int recSize = li.size();
for (int i = 0; i < recSize; i++) {
int j = i;
if (!isServer) { // on client side the order is reversed
j = recSize - i - 1;
}
RecordRouteHeader rr = (RecordRouteHeader) li.elementAt(j);
Address addr = rr.getAddress();
RouteHeader route = new RouteHeader();
route.setAddress((Address)rr.getAddress().clone());
route.setParameters((NameValueList)rr.getParameters().clone());
routeList.add(route);
}
RouteHeader firstRoute = (RouteHeader) routeList.getFirst();
if (!((SipURI)firstRoute.getAddress().getURI()).hasLrParam()) {
RouteHeader route = new RouteHeader();
route.setAddress((Address)contact.getAddress().clone());
routeList.removeFirst();
// IMPL_NOTE: is clone() need?
URI uri = firstRoute.getAddress().getURI();
request.setRequestURI(uri);
routeList.add(route);
request.addHeader(routeList);
} else {
URI uri = (URI) contact.getAddress().getURI().clone();
request.setRequestURI(uri);
request.addHeader(routeList);
}
}
|
public void | close()Closes the encapsulated channel.
encapsulatedChannel.close();
|
protected final void | disableRetransmissionTimer()Turns off retransmission events for this transaction.
retransmissionTimerTicksLeft = -1;
|
protected final void | disableTimeoutTimer()Disabled the timeout timer.
timeoutTimerTicksLeft = -1;
|
public boolean | doesCancelMatchTransaction(Request requestToHeaderTest)A method that can be used to test if an incoming request
belongs to this transction. This does not take the transaction
state into account when doing the check otherwise it is identical
to isMessagePartOfTransaction. This is useful for checking if
a CANCEL belongs to this transaction.
// List of Via headers in the message to test
ViaList viaHeaders;
// ToHeaderpmost Via header in the list
ViaHeader topViaHeader;
// Branch code in the topmost Via header
String messageBranch;
// Flags whether the select message is part of this transaction
boolean transactionMatches;
transactionMatches = false;
if (getOriginalRequest() == null ||
getOriginalRequest().getMethod().equals(Request.CANCEL)) {
return false;
}
// Get the topmost Via header and its branch parameter
viaHeaders = requestToHeaderTest.getViaHeaders();
if (viaHeaders != null) {
topViaHeader = (ViaHeader)viaHeaders.getFirst();
messageBranch = topViaHeader.getBranch();
if (messageBranch != null) {
// If the branch parameter exists but
// does not start with the magic cookie,
if (!messageBranch.toUpperCase().startsWith(SIPConstants.
GENERAL_BRANCH_MAGIC_COOKIE.toUpperCase())) {
// Flags this as old
// (RFC2543-compatible) client
// version
messageBranch = null;
}
}
// If a new branch parameter exists,
if (messageBranch != null &&
this.getBranch() != null) {
// If the branch equals the branch in
// this message,
if (getBranch().equals(messageBranch)
&& topViaHeader.getSentBy().
equals(((ViaHeader)getOriginalRequest().
getViaHeaders().getFirst()).
getSentBy())) {
transactionMatches = true;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_JSR180, "returning true");
}
}
} else {
// If this is an RFC2543-compliant message,
// If RequestURI, ToHeader tag, FromHeader tag,
// CallIdHeader, CSeqHeader number, and top Via
// headers are the same,
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"testing against " + getOriginalRequest());
}
if (
getOriginalRequest().getRequestURI().equals
(requestToHeaderTest.getRequestURI()) &&
getOriginalRequest().getTo().equals
(requestToHeaderTest.getTo()) &&
getOriginalRequest().getFromHeader().equals
(requestToHeaderTest.getFromHeader()) &&
getOriginalRequest().getCallId().
getCallId().equals
(requestToHeaderTest.getCallId() .getCallId()) &&
getOriginalRequest().
getCSeqHeader().getSequenceNumber() ==
requestToHeaderTest.getCSeqHeader().
getSequenceNumber() &&
topViaHeader.equals
(getOriginalRequest().
getViaHeaders().getFirst())) {
transactionMatches = true;
}
}
}
return transactionMatches;
|
protected final void | enableRetransmissionTimer()Enables retransmission timer events for this transaction to begin in
one tick.
enableRetransmissionTimer(1);
|
protected final void | enableRetransmissionTimer(int tickCount)Enables retransmission timer events for this
transaction to begin after the number of ticks passed to
this routine.
retransmissionTimerTicksLeft =
Math.min(tickCount, MAXIMUM_RETRANSMISSION_TICK_COUNT);
retransmissionTimerLastTickCount =
retransmissionTimerTicksLeft;
|
protected final void | enableTimeoutTimer(int tickCount)Enables a timeout event to occur for this transaction after the number
of ticks passed to this method.
timeoutTimerTicksLeft = tickCount;
|
protected abstract void | fireRetransmissionTimer()This method is called when this transaction's
retransmission timer has fired.
|
protected abstract void | fireTimeoutTimer()This method is called when this transaction's
timeout timer has fired.
|
final synchronized void | fireTimer()Fired after each timer tick.
Checks the retransmission and timeout
timers of this transaction, and fired these events
if necessary.
// If the timeout timer is enabled,
if (timeoutTimerTicksLeft != -1) {
// Count down the timer, and if it has run out,
if (--timeoutTimerTicksLeft == 0) {
// Fire the timeout timer
fireTimeoutTimer();
}
}
// If the retransmission timer is enabled,
if (retransmissionTimerTicksLeft != -1) {
// Count down the timer, and if it has run out,
if (--retransmissionTimerTicksLeft == 0) {
// Enable this timer to fire again after
// twice the original time
enableRetransmissionTimer
(retransmissionTimerLastTickCount * 2);
// Fire the timeout timer
fireRetransmissionTimer();
}
}
|
public java.lang.Object | getApplicationData()Retrieves the application data.
return applicationData;
|
public final java.lang.String | getBranch()Gets the current setting for the branch parameter of this transaction.
if (branch == null) {
branch = getOriginalRequest().getTopmostVia().getBranch();
}
return branch;
|
public java.lang.String | getBranchId()Gets the branch identifier.
return branch;
|
public Dialog | getDialog()Gets the dialog object of this Transaction object. This object
returns null if no dialog exists. A dialog only exists for a
transaction when a session is setup between a User Agent Client and a
User Agent Server, either by a 1xx Provisional Response for an early
dialog or a 200OK Response for a committed dialog.
return dialog;
|
public java.lang.String | getHost()Gets the host.
return encapsulatedChannel.getHost();
|
public java.lang.String | getKey()Gets the key.
return encapsulatedChannel.getKey();
|
public Response | getLastResponse()Gets the last response. return this.lastResponse;
|
public MessageChannel | getMessageChannel()Returns the message channel used for
transmitting/receiving messages
for this transaction. Made public in support of JAIN dual
transaction model.
return encapsulatedChannel;
|
public MessageProcessor | getMessageProcessor()Gets the message processor handling this transaction.
return encapsulatedChannel.getMessageProcessor();
|
public Request | getOriginalRequest()Gets the request being handled by this transaction.
return originalRequest;
|
public java.lang.String | getPeerAddress()Gets the remote address.
return encapsulatedChannel.getPeerAddress();
|
public int | getPeerPort()Gets the remote port number.
return encapsulatedChannel.getPeerPort();
|
public int | getPort()Gets the port.
return encapsulatedChannel.getPort();
|
public Request | getRequest()Gets the original request but cast to a Request structure.
return (Request) originalRequest;
|
public int | getRetransmitTimer()Returns the current value of the retransmit timer in
milliseconds used to retransmit messages over unreliable transports.
return SIPTransactionStack.BASE_TIMER_INTERVAL;
|
public SIPMessageStack | getSIPStack()Gets the SIP stack context.
return parentStack;
|
public final int | getState()Gets the current state of this transaction.
return currentState;
|
public java.lang.String | getTransactionId()Gets the transaction Id.
return getOriginalRequest().getTransactionId();
|
public java.lang.String | getTransport()Gets the connection transport.
return encapsulatedChannel.getTransport();
|
public ViaHeader | getViaHeader()Returns the Via header for this channel. Gets the Via header of the
underlying message channel, and adds a branch parameter to it for this
transaction.
// Via header of the encapulated channel
ViaHeader channelViaHeader;
// Add the branch parameter to the underlying
// channel's Via header
channelViaHeader = super.getViaHeader();
channelViaHeader.setBranch(branch);
return channelViaHeader;
|
public java.lang.String | getViaHost()Gets the host to assign for an outgoing Request via header.
return getViaHeader().getHost();
|
public int | getViaPort()Gets the port to assign for the via header of an outgoing message.
return getViaHeader().getPort();
|
public void | handleException(SIPServerException ex)Process an exception.
encapsulatedChannel.handleException(ex);
|
public boolean | isAckSeen()Checks if the ACK has been seen flag is set.
return ackSeenFlag;
|
protected final boolean | isByeTransaction()Returns a flag that states if this is a BYE transaction.
return originalRequest.getMethod().equals(Request.BYE);
|
protected final boolean | isCancelTransaction()Returns true if the transaction corresponds to a CANCEL message.
return originalRequest.getMethod().equals(Request.CANCEL);
|
protected final boolean | isInviteTransaction()Returns a flag stating whether this transaction is for an
INVITE request or not.
return originalRequest.getMethod().equals(Request.INVITE);
|
public abstract boolean | isMessagePartOfTransaction(Message messageToHeaderTest)Tests a message to see if it is part of this transaction.
|
public boolean | isReliable()Checks if the connection is reliable
return encapsulatedChannel.isReliable();
|
public boolean | isSecure()Check if this connection is secure.
return encapsulatedChannel.isSecure();
|
protected final boolean | isTerminated()Tests if this transaction has terminated.
return (getState() == TERMINATED_STATE);
|
public boolean | passToListener()Checks if transaction has been sent to the listener.
return toListener;
|
protected void | raiseErrorEvent(int errorEventID)Creates a SIPTransactionErrorEvent and sends it
to all of the listeners of this transaction.
This method also flags the transaction as
terminated.
// Error event to send to all listeners
SIPTransactionErrorEvent newErrorEvent;
// Iterator through the list of listeners
Enumeration listenerIterator;
// Next listener in the list
SIPTransactionEventListener nextListener;
// Create the error event
newErrorEvent = new SIPTransactionErrorEvent(this,
errorEventID);
// Loop through all listeners of this transaction
synchronized (eventListeners) {
listenerIterator = eventListeners.elements();
while (listenerIterator.hasMoreElements()) {
// Send the event to the next listener
nextListener = (SIPTransactionEventListener)
listenerIterator.nextElement();
nextListener.transactionErrorEvent
(newErrorEvent);
}
}
// Clear the event listeners after propagating the error.
eventListeners.removeAllElements();
// Errors always terminate a transaction
setState(TERMINATED_STATE);
if (this instanceof ServerTransaction &&
this.isByeTransaction() && this.dialog != null)
this.dialog.setState(Dialog.TERMINATED_STATE);
|
public void | removeEventListener(SIPTransactionEventListener oldListener)Removes an event listener from this transaction.
eventListeners.removeElement(oldListener);
|
public abstract void | sendMessage(Message messageToHeaderSend)Processes the message through the transaction and sends it to the SIP
peer.
|
protected void | sendMessage(byte[] messageBytes, java.lang.String receiverAddress, int receiverPort)Parses the byte array as a message, process it through the
transaction, and send it to the SIP peer.
// Object representation of the SIP message
Message messageToHeaderSend;
try {
StringMsgParser messageParser = new StringMsgParser();
messageToHeaderSend =
messageParser.parseSIPMessage(messageBytes);
sendMessage(messageToHeaderSend);
} catch (ParseException e) {
throw new IOException(e.getMessage());
}
|
public void | setAckSeen()Sets the ACK has been seen flag.
ackSeenFlag = true;
|
public void | setApplicationData(java.lang.Object newApplicationData)Sets the application data.
applicationData = newApplicationData;
|
public final void | setBranch(java.lang.String newBranch)Sets the Via header branch parameter used to identify
this transaction.
branch = newBranch;
|
public void | setDialog(Dialog newDialog)Sets the dialog object.
dialog = newDialog;
|
public void | setOriginalRequest(Request newOriginalRequest)Sets the request message that this transaction handles.
// Branch value of topmost Via header
String newBranch;
originalRequest = newOriginalRequest;
originalRequest.setTransaction(this);
// If the message has an explicit branch value set,
newBranch = ((ViaHeader)newOriginalRequest.getViaHeaders().
getFirst()).getBranch();
if (newBranch != null) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"Setting Branch id : " + newBranch);
}
// Override the default branch with the one
// set by the message
setBranch(newBranch);
} else {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"Branch id is null!" + newOriginalRequest.encode());
}
}
|
public void | setState(int newState)Changes the state of this transaction.
currentState = newState;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"setState " + this + " " + newState);
}
// If this transaction is being terminated,
if (newState == TERMINATED_STATE) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"Transaction is being terminated!");
// new Exception().printStackTrace();
}
}
|