001: /*
002: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
003: * Reserved. Use is subject to license terms.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: package gov.nist.siplite.stack;
026:
027: import gov.nist.siplite.parser.*;
028: import gov.nist.siplite.header.*;
029: import gov.nist.siplite.message.*;
030: import gov.nist.siplite.*;
031: import gov.nist.siplite.address.*;
032: import gov.nist.core.*;
033: import java.util.*;
034:
035: import java.io.IOException;
036: import javax.microedition.sip.SipException;
037:
038: import com.sun.midp.log.Logging;
039: import com.sun.midp.log.LogChannels;
040:
041: /**
042: * Abstract class to support both client and server transactions.
043: * Provides an encapsulation of a message channel, handles timer events,
044: * and creation of the Via header for a message.
045: *
046: * @version JAIN-SIP-1.1
047: *
048: */
049: public abstract class Transaction extends MessageChannel {
050: /** Transaction timer interval. */
051: protected static final int BASE_TIMER_INTERVAL = SIPTransactionStack.BASE_TIMER_INTERVAL;
052: /** RTT Estimate. 500ms default. */
053: protected static final int T1 = 500 / BASE_TIMER_INTERVAL;
054: /** 5 sec Maximum duration a message will remain in the network */
055: protected static final int T4 = 5000 / BASE_TIMER_INTERVAL;
056: /**
057: * The maximum retransmit interval for non-INVITE
058: * requests and INVITE responses
059: */
060: protected static final int T2 = 4000 / BASE_TIMER_INTERVAL;
061: /** INVITE request retransmit interval, for UDP only */
062: protected static final int TIMER_A = 1 * T1;
063: /** INVITE transaction timeout timer */
064: protected static final int TIMER_B = 64 * T1;
065: /** INVITE transaction timeout timer */
066: protected static final int TIMER_J = 64 * T1;
067: /** INVITE transaction timeout timer */
068: protected static final int TIMER_F = 64 * T1;
069: /** INVITE transaction timeout timer */
070: protected static final int TIMER_H = 64 * T1;
071: /** INVITE transaction timeout timer */
072: protected static final int TIMER_I = T4;
073: /** INVITE transaction timeout timer */
074: protected static final int TIMER_K = T4;
075: /** INVITE transaction timeout timer */
076: protected static final int TIMER_D = 32000 / BASE_TIMER_INTERVAL;
077: /** INVITE transaction timeout timer */
078: protected static final int TIMER_C = 3 * 60 * 1000 / BASE_TIMER_INTERVAL;
079: /** Last response message. */
080: protected Response lastResponse;
081: /** Current SIP dialog. */
082: protected Dialog dialog;
083: /** Flag indicating an ACK was received. */
084: protected boolean ackSeenFlag;
085: /** Flag indicating listener waiting. */
086: protected boolean toListener;
087: /**
088: * Initialized but no state assigned.
089: */
090: public static final int INITIAL_STATE = -1;
091: /**
092: * Trying state.
093: */
094: public static final int TRYING_STATE = 1;
095: /**
096: * CALLING State.
097: */
098: public static final int CALLING_STATE = 2;
099: /**
100: * Proceeding state.
101: */
102: public static final int PROCEEDING_STATE = 3;
103: /**
104: * Completed state.
105: */
106: public static final int COMPLETED_STATE = 4;
107: /**
108: * Confirmed state.
109: */
110: public static final int CONFIRMED_STATE = 5;
111: /**
112: * Terminated state.
113: */
114: public static final int TERMINATED_STATE = 6;
115: /**
116: * Maximum number of ticks between retransmissions.
117: */
118: protected static final int MAXIMUM_RETRANSMISSION_TICK_COUNT = 4000 / BASE_TIMER_INTERVAL;
119: /** Parent stack for this transaction. */
120: protected SIPTransactionStack parentStack;
121: /** Original request that is being handled by this transaction. */
122: private Request originalRequest;
123: /**
124: * Underlying channel being used to send messages for this
125: * transaction.
126: */
127: protected MessageChannel encapsulatedChannel;
128: /** Transaction branch ID. */
129: private String branch;
130: /** Current transaction state. */
131: private int currentState;
132: /** Number of ticks the retransmission timer was set to last. */
133: private int retransmissionTimerLastTickCount;
134: /** Number of ticks before the message is retransmitted. */
135: private int retransmissionTimerTicksLeft;
136: /** Number of ticks before the transaction times out. */
137: private int timeoutTimerTicksLeft;
138: /** List of event listeners for this transaction. */
139: private Vector eventListeners;
140: /** Flag to indcate that this has been cancelled. */
141: protected boolean isCancelled;
142: /**
143: * Object representing the connection being held by the JSR180
144: * Implementation It can be either a SipClientConnection in case
145: * of a ClientTransaction or a SipConnectionNotifier in case of a
146: *ServerTransaction.
147: */
148: protected Object applicationData;
149:
150: /**
151: * Retrieves the application data.
152: * @return Object representing the connection being held by the JSR180
153: * Implementation. It can be either a SipClientConnection in case of a
154: * ClientTransaction or a SipConnectionNotifier in case of a
155: * ServerTransaction
156: */
157: public Object getApplicationData() {
158: return applicationData;
159: }
160:
161: /**
162: * Sets the application data.
163: * @param newApplicationData Object representing the connection being held
164: * by the JSR180
165: * Implementation. It can be either a SipClientConnection in case of a
166: * ClientTransaction or a SipConnectionNotifier in case of a
167: * ServerTransaction
168: */
169: public void setApplicationData(Object newApplicationData) {
170: applicationData = newApplicationData;
171: }
172:
173: /**
174: * Gets the branch identifier.
175: * @return the current branch id
176: */
177: public String getBranchId() {
178: return branch;
179: }
180:
181: /**
182: * Transaction constructor.
183: *
184: * @param newParentStack Parent stack for this transaction.
185: * @param newEncapsulatedChannel
186: * Underlying channel for this transaction.
187: */
188: protected Transaction(SIPTransactionStack newParentStack,
189: MessageChannel newEncapsulatedChannel) {
190: parentStack = newParentStack;
191: encapsulatedChannel = newEncapsulatedChannel;
192: currentState = INITIAL_STATE;
193: disableRetransmissionTimer();
194: disableTimeoutTimer();
195: eventListeners = new Vector();
196: // Always add the parent stack as a listener
197: // of this transaction
198: addEventListener(newParentStack);
199: }
200:
201: /**
202: * Sets the request message that this transaction handles.
203: *
204: * @param newOriginalRequest Request being handled.
205: */
206: public void setOriginalRequest(Request newOriginalRequest) {
207: // Branch value of topmost Via header
208: String newBranch;
209:
210: originalRequest = newOriginalRequest;
211: originalRequest.setTransaction(this );
212: // If the message has an explicit branch value set,
213: newBranch = ((ViaHeader) newOriginalRequest.getViaHeaders()
214: .getFirst()).getBranch();
215: if (newBranch != null) {
216: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
217: Logging.report(Logging.INFORMATION,
218: LogChannels.LC_JSR180, "Setting Branch id : "
219: + newBranch);
220: }
221:
222: // Override the default branch with the one
223: // set by the message
224: setBranch(newBranch);
225: } else {
226: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
227: Logging.report(Logging.INFORMATION,
228: LogChannels.LC_JSR180, "Branch id is null!"
229: + newOriginalRequest.encode());
230: }
231: }
232: }
233:
234: /**
235: * Gets the request being handled by this transaction.
236: * @return Request being handled.
237: */
238: public Request getOriginalRequest() {
239: return originalRequest;
240: }
241:
242: /**
243: * Gets the original request but cast to a Request structure.
244: * @return the request that generated this transaction.
245: */
246: public Request getRequest() {
247: return (Request) originalRequest;
248: }
249:
250: /**
251: * Returns a flag stating whether this transaction is for an
252: * INVITE request or not.
253: * @return True if this is an INVITE request, false if not.
254: */
255: protected final boolean isInviteTransaction() {
256: return originalRequest.getMethod().equals(Request.INVITE);
257: }
258:
259: /**
260: * Returns true if the transaction corresponds to a CANCEL message.
261: * @return true if the transaciton is a CANCEL transaction.
262: */
263: protected final boolean isCancelTransaction() {
264: return originalRequest.getMethod().equals(Request.CANCEL);
265: }
266:
267: /**
268: * Returns a flag that states if this is a BYE transaction.
269: * @return true if the transaciton is a BYE transaction.
270: */
271: protected final boolean isByeTransaction() {
272: return originalRequest.getMethod().equals(Request.BYE);
273: }
274:
275: /**
276: * Returns the message channel used for
277: * transmitting/receiving messages
278: * for this transaction. Made public in support of JAIN dual
279: * transaction model.
280: * @return Encapsulated MessageChannel.
281: */
282: public MessageChannel getMessageChannel() {
283: return encapsulatedChannel;
284: }
285:
286: /**
287: * Sets the Via header branch parameter used to identify
288: * this transaction.
289: * @param newBranch New string used as the branch
290: * for this transaction.
291: */
292: public final void setBranch(String newBranch) {
293: branch = newBranch;
294: }
295:
296: /**
297: * Gets the current setting for the branch parameter of this transaction.
298: * @return Branch parameter for this transaction.
299: */
300: public final String getBranch() {
301: if (branch == null) {
302: branch = getOriginalRequest().getTopmostVia().getBranch();
303: }
304: return branch;
305: }
306:
307: /**
308: * Changes the state of this transaction.
309: * @param newState New state of this transaction.
310: */
311: public void setState(int newState) {
312: currentState = newState;
313:
314: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
315: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
316: "setState " + this + " " + newState);
317: }
318:
319: // If this transaction is being terminated,
320: if (newState == TERMINATED_STATE) {
321: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
322: Logging.report(Logging.INFORMATION,
323: LogChannels.LC_JSR180,
324: "Transaction is being terminated!");
325: // new Exception().printStackTrace();
326: }
327: }
328: }
329:
330: /**
331: * Gets the current state of this transaction.
332: * @return Current state of this transaction.
333: */
334: public final int getState() {
335: return currentState;
336: }
337:
338: /**
339: * Enables retransmission timer events for this transaction to begin in
340: * one tick.
341: */
342: protected final void enableRetransmissionTimer() {
343: enableRetransmissionTimer(1);
344: }
345:
346: /**
347: * Enables retransmission timer events for this
348: * transaction to begin after the number of ticks passed to
349: * this routine.
350: * @param tickCount Number of ticks before the
351: * next retransmission timer
352: * event occurs.
353: */
354: protected final void enableRetransmissionTimer(int tickCount) {
355: retransmissionTimerTicksLeft = Math.min(tickCount,
356: MAXIMUM_RETRANSMISSION_TICK_COUNT);
357: retransmissionTimerLastTickCount = retransmissionTimerTicksLeft;
358: }
359:
360: /**
361: * Turns off retransmission events for this transaction.
362: */
363: protected final void disableRetransmissionTimer() {
364: retransmissionTimerTicksLeft = -1;
365: }
366:
367: /**
368: * Enables a timeout event to occur for this transaction after the number
369: * of ticks passed to this method.
370: * @param tickCount Number of ticks before this transaction times out.
371: */
372: protected final void enableTimeoutTimer(int tickCount) {
373: timeoutTimerTicksLeft = tickCount;
374: }
375:
376: /**
377: * Disabled the timeout timer.
378: */
379: protected final void disableTimeoutTimer() {
380: timeoutTimerTicksLeft = -1;
381: }
382:
383: /**
384: * Fired after each timer tick.
385: * Checks the retransmission and timeout
386: * timers of this transaction, and fired these events
387: * if necessary.
388: */
389: synchronized final void fireTimer() {
390: // If the timeout timer is enabled,
391: if (timeoutTimerTicksLeft != -1) {
392: // Count down the timer, and if it has run out,
393: if (--timeoutTimerTicksLeft == 0) {
394: // Fire the timeout timer
395: fireTimeoutTimer();
396: }
397: }
398: // If the retransmission timer is enabled,
399: if (retransmissionTimerTicksLeft != -1) {
400: // Count down the timer, and if it has run out,
401: if (--retransmissionTimerTicksLeft == 0) {
402: // Enable this timer to fire again after
403: // twice the original time
404: enableRetransmissionTimer(retransmissionTimerLastTickCount * 2);
405: // Fire the timeout timer
406: fireRetransmissionTimer();
407: }
408: }
409: }
410:
411: /**
412: * Tests a message to see if it is part of this transaction.
413: * @param messageToHeaderTest message to be processed
414: * @return True if the message is part of this
415: * transaction, false if not.
416: */
417: public abstract boolean isMessagePartOfTransaction(
418: Message messageToHeaderTest);
419:
420: /**
421: * This method is called when this transaction's
422: * retransmission timer has fired.
423: */
424: protected abstract void fireRetransmissionTimer();
425:
426: /**
427: * This method is called when this transaction's
428: * timeout timer has fired.
429: */
430: protected abstract void fireTimeoutTimer();
431:
432: /**
433: * Tests if this transaction has terminated.
434: * @return Trus if this transaction is terminated, false if not.
435: */
436: protected final boolean isTerminated() {
437: return (getState() == TERMINATED_STATE);
438: }
439:
440: /**
441: * Gets the host.
442: * @return the host
443: */
444: public String getHost() {
445: return encapsulatedChannel.getHost();
446: }
447:
448: /**
449: * Gets the key.
450: * @return the key
451: */
452: public String getKey() {
453: return encapsulatedChannel.getKey();
454: }
455:
456: /**
457: * Gets the port.
458: * @return the port
459: */
460: public int getPort() {
461: return encapsulatedChannel.getPort();
462: }
463:
464: /**
465: * Gets the SIP stack context.
466: * @return the SIP Stack
467: */
468: public SIPMessageStack getSIPStack() {
469: return parentStack;
470: }
471:
472: /**
473: * Gets the remote address.
474: * @return the remote address
475: */
476: public String getPeerAddress() {
477: return encapsulatedChannel.getPeerAddress();
478: }
479:
480: /**
481: * Gets the remote port number.
482: * @return the remote port number
483: */
484: public int getPeerPort() {
485: return encapsulatedChannel.getPeerPort();
486: }
487:
488: /**
489: * Gets the connection transport.
490: * @return the connection transport
491: */
492: public String getTransport() {
493: return encapsulatedChannel.getTransport();
494: }
495:
496: /**
497: * Checks if the connection is reliable
498: * @return true if channel is on a stream connection
499: */
500: public boolean isReliable() {
501: return encapsulatedChannel.isReliable();
502: }
503:
504: /**
505: * Returns the Via header for this channel. Gets the Via header of the
506: * underlying message channel, and adds a branch parameter to it for this
507: * transaction.
508: * @return the via header
509: */
510: public ViaHeader getViaHeader() {
511: // Via header of the encapulated channel
512: ViaHeader channelViaHeader;
513: // Add the branch parameter to the underlying
514: // channel's Via header
515: channelViaHeader = super .getViaHeader();
516: channelViaHeader.setBranch(branch);
517: return channelViaHeader;
518: }
519:
520: /**
521: * Process an exception.
522: * @param ex the exception to handle
523: */
524: public void handleException(SIPServerException ex) {
525: encapsulatedChannel.handleException(ex);
526: }
527:
528: /**
529: * Processes the message through the transaction and sends it to the SIP
530: * peer.
531: * @param messageToHeaderSend Message to send to the SIP peer.
532: */
533: abstract public void sendMessage(Message messageToHeaderSend)
534: throws IOException;
535:
536: /**
537: * Parses the byte array as a message, process it through the
538: * transaction, and send it to the SIP peer.
539: *
540: * @param messageBytes Bytes of the message to send.
541: * @param receiverAddress Address of the target peer.
542: * @param receiverPort Network port of the target peer.
543: *
544: * @throws IOException If there is an error parsing
545: * the byte array into an object.
546: */
547: protected void sendMessage(byte[] messageBytes,
548: String receiverAddress, int receiverPort)
549: throws IOException {
550: // Object representation of the SIP message
551: Message messageToHeaderSend;
552: try {
553: StringMsgParser messageParser = new StringMsgParser();
554: messageToHeaderSend = messageParser
555: .parseSIPMessage(messageBytes);
556: sendMessage(messageToHeaderSend);
557: } catch (ParseException e) {
558: throw new IOException(e.getMessage());
559: }
560: }
561:
562: /**
563: * Adds a new event listener to this transaction.
564: * @param newListener Listener to add.
565: */
566: public void addEventListener(SIPTransactionEventListener newListener) {
567: eventListeners.addElement(newListener);
568: }
569:
570: /**
571: * Removes an event listener from this transaction.
572: * @param oldListener Listener to remove.
573: */
574: public void removeEventListener(
575: SIPTransactionEventListener oldListener) {
576: eventListeners.removeElement(oldListener);
577: }
578:
579: /**
580: * Creates a SIPTransactionErrorEvent and sends it
581: * to all of the listeners of this transaction.
582: * This method also flags the transaction as
583: * terminated.
584: * @param errorEventID ID of the error to raise.
585: */
586: protected void raiseErrorEvent(int errorEventID) {
587: // Error event to send to all listeners
588: SIPTransactionErrorEvent newErrorEvent;
589: // Iterator through the list of listeners
590: Enumeration listenerIterator;
591: // Next listener in the list
592: SIPTransactionEventListener nextListener;
593: // Create the error event
594: newErrorEvent = new SIPTransactionErrorEvent(this , errorEventID);
595: // Loop through all listeners of this transaction
596: synchronized (eventListeners) {
597: listenerIterator = eventListeners.elements();
598: while (listenerIterator.hasMoreElements()) {
599: // Send the event to the next listener
600: nextListener = (SIPTransactionEventListener) listenerIterator
601: .nextElement();
602: nextListener.transactionErrorEvent(newErrorEvent);
603: }
604: }
605: // Clear the event listeners after propagating the error.
606: eventListeners.removeAllElements();
607: // Errors always terminate a transaction
608: setState(TERMINATED_STATE);
609: if (this instanceof ServerTransaction
610: && this .isByeTransaction() && this .dialog != null)
611: this .dialog.setState(Dialog.TERMINATED_STATE);
612: }
613:
614: /**
615: * A shortcut way of telling if we are a server transaction.
616: * @return true if this is a servertransaction
617: */
618: protected boolean IsServerTransaction() {
619: return this instanceof ServerTransaction;
620: }
621:
622: /**
623: * Gets the dialog object of this Transaction object. This object
624: * returns null if no dialog exists. A dialog only exists for a
625: * transaction when a session is setup between a User Agent Client and a
626: * User Agent Server, either by a 1xx Provisional Response for an early
627: * dialog or a 200OK Response for a committed dialog.
628: * @return the Dialog Object of this Transaction object.
629: * @see Dialog
630: */
631: public Dialog getDialog() {
632: return dialog;
633: }
634:
635: /**
636: * Sets the dialog object.
637: * @param newDialog the dialog to set.
638: */
639: public void setDialog(Dialog newDialog) {
640: dialog = newDialog;
641: }
642:
643: /**
644: * Returns the current value of the retransmit timer in
645: * milliseconds used to retransmit messages over unreliable transports.
646: * @return the integer value of the retransmit timer in milliseconds.
647: */
648: public int getRetransmitTimer() {
649: return SIPTransactionStack.BASE_TIMER_INTERVAL;
650: }
651:
652: /**
653: * Gets the host to assign for an outgoing Request via header.
654: * @return the via host
655: */
656: public String getViaHost() {
657: return getViaHeader().getHost();
658: }
659:
660: /**
661: * Gets the last response.
662: * @return the last response
663: */
664: public Response getLastResponse() {
665: return this .lastResponse;
666: }
667:
668: /**
669: * Gets the transaction Id.
670: * @return the transaction id
671: */
672: public String getTransactionId() {
673: return getOriginalRequest().getTransactionId();
674: }
675:
676: /**
677: * Gets the port to assign for the via header of an outgoing message.
678: * @return the via port number
679: */
680: public int getViaPort() {
681: return getViaHeader().getPort();
682: }
683:
684: /**
685: * A method that can be used to test if an incoming request
686: * belongs to this transction. This does not take the transaction
687: * state into account when doing the check otherwise it is identical
688: * to isMessagePartOfTransaction. This is useful for checking if
689: * a CANCEL belongs to this transaction.
690: * @param requestToHeaderTest is the request to test.
691: * @return true if the the request belongs to the transaction.
692: */
693: public boolean doesCancelMatchTransaction(
694: Request requestToHeaderTest) {
695: // List of Via headers in the message to test
696: ViaList viaHeaders;
697: // ToHeaderpmost Via header in the list
698: ViaHeader topViaHeader;
699: // Branch code in the topmost Via header
700: String messageBranch;
701: // Flags whether the select message is part of this transaction
702: boolean transactionMatches;
703: transactionMatches = false;
704:
705: if (getOriginalRequest() == null
706: || getOriginalRequest().getMethod().equals(
707: Request.CANCEL)) {
708: return false;
709: }
710:
711: // Get the topmost Via header and its branch parameter
712: viaHeaders = requestToHeaderTest.getViaHeaders();
713: if (viaHeaders != null) {
714: topViaHeader = (ViaHeader) viaHeaders.getFirst();
715: messageBranch = topViaHeader.getBranch();
716: if (messageBranch != null) {
717: // If the branch parameter exists but
718: // does not start with the magic cookie,
719: if (!messageBranch.toUpperCase().startsWith(
720: SIPConstants.GENERAL_BRANCH_MAGIC_COOKIE
721: .toUpperCase())) {
722: // Flags this as old
723: // (RFC2543-compatible) client
724: // version
725: messageBranch = null;
726: }
727: }
728: // If a new branch parameter exists,
729: if (messageBranch != null && this .getBranch() != null) {
730: // If the branch equals the branch in
731: // this message,
732: if (getBranch().equals(messageBranch)
733: && topViaHeader.getSentBy().equals(
734: ((ViaHeader) getOriginalRequest()
735: .getViaHeaders().getFirst())
736: .getSentBy())) {
737: transactionMatches = true;
738:
739: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
740: Logging
741: .report(Logging.INFORMATION,
742: LogChannels.LC_JSR180,
743: "returning true");
744: }
745: }
746: } else {
747: // If this is an RFC2543-compliant message,
748: // If RequestURI, ToHeader tag, FromHeader tag,
749: // CallIdHeader, CSeqHeader number, and top Via
750: // headers are the same,
751: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
752: Logging.report(Logging.INFORMATION,
753: LogChannels.LC_JSR180, "testing against "
754: + getOriginalRequest());
755: }
756:
757: if (
758:
759: getOriginalRequest().getRequestURI().equals(
760: requestToHeaderTest.getRequestURI())
761: && getOriginalRequest().getTo().equals(
762: requestToHeaderTest.getTo())
763: && getOriginalRequest().getFromHeader().equals(
764: requestToHeaderTest.getFromHeader())
765: && getOriginalRequest().getCallId().getCallId()
766: .equals(
767: requestToHeaderTest.getCallId()
768: .getCallId())
769: && getOriginalRequest().getCSeqHeader()
770: .getSequenceNumber() == requestToHeaderTest
771: .getCSeqHeader().getSequenceNumber()
772: && topViaHeader.equals(getOriginalRequest()
773: .getViaHeaders().getFirst())) {
774: transactionMatches = true;
775: }
776: }
777: }
778: return transactionMatches;
779: }
780:
781: /**
782: * Checks if transaction has been sent to the listener.
783: * @return true if transaction has been sent
784: */
785: public boolean passToListener() {
786: return toListener;
787: }
788:
789: /**
790: * Closes the encapsulated channel.
791: */
792: public void close() {
793: encapsulatedChannel.close();
794: }
795:
796: /**
797: * Check if this connection is secure.
798: * @return true if this is a secure channel
799: */
800: public boolean isSecure() {
801: return encapsulatedChannel.isSecure();
802: }
803:
804: /**
805: * Gets the message processor handling this transaction.
806: * @return the mesage processor for this transaction
807: */
808: public MessageProcessor getMessageProcessor() {
809: return encapsulatedChannel.getMessageProcessor();
810: }
811:
812: /**
813: * Sets the ACK has been seen flag.
814: */
815: public void setAckSeen() {
816: ackSeenFlag = true;
817: }
818:
819: /**
820: * Checks if the ACK has been seen flag is set.
821: * @return true if the ACK has been seen
822: */
823: public boolean isAckSeen() {
824: return ackSeenFlag;
825: }
826:
827: /**
828: * Create route set for request.
829: *
830: * @param request the input request
831: * @throws SipException if any occurs
832: */
833: protected void buildRouteSet(Request request) throws SipException {
834: Message origMsg = lastResponse;
835: boolean isServer = false;
836: Dialog dlg = getDialog();
837:
838: if (dlg != null) { // inside of dialog
839: Transaction firstTransaction = dlg.getFirstTransaction();
840: if (dlg.isServer()) { // dialog was created on server side
841: origMsg = firstTransaction.getOriginalRequest();
842: isServer = true;
843: } else { // dialog was created on client side
844: origMsg = firstTransaction.getLastResponse();
845: }
846: } else { // out of dialog
847: // IMPL_NOTE: implement a support for the case when Contact
848: // header is not present.
849: if (this instanceof ServerTransaction) {
850: origMsg = getOriginalRequest();
851: isServer = true;
852: }
853: }
854:
855: if (origMsg == null) {
856: // Avoid NPE in case when sending ACK from the part that
857: // initiated a Re-INVITE.
858: return;
859: }
860:
861: RecordRouteList recordRouteList = origMsg
862: .getRecordRouteHeaders();
863: ContactList cl = origMsg.getContactHeaders();
864:
865: if (cl == null) {
866: // Prevent NPE and log an error: Contact header is absent.
867: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
868: Logging
869: .report(Logging.ERROR, LogChannels.LC_JSR180,
870: "Transaction.buildRouteSet(): Contact must be present!");
871: }
872: return;
873: }
874:
875: ContactHeader contact = (ContactHeader) cl.getFirst();
876:
877: if (recordRouteList == null) {
878: URI remoteTarget = contact.getAddress().getURI();
879:
880: // RFC 3261, 12.2.1.1 Generating the Request
881: // If the route set is empty, the UAC MUST place the remote
882: // target URI into the Request-URI. The UAC MUST NOT add
883: // a Route header field to the request.
884: request.setRequestURI(remoteTarget);
885: } else {
886: request.removeHeader(Header.ROUTE);
887:
888: RouteList routeList = new RouteList();
889: // start at the end of the list and walk backwards
890: Vector li = recordRouteList.getHeaders();
891:
892: int recSize = li.size();
893: for (int i = 0; i < recSize; i++) {
894: int j = i;
895: if (!isServer) { // on client side the order is reversed
896: j = recSize - i - 1;
897: }
898: RecordRouteHeader rr = (RecordRouteHeader) li
899: .elementAt(j);
900: Address addr = rr.getAddress();
901: RouteHeader route = new RouteHeader();
902: route.setAddress((Address) rr.getAddress().clone());
903: route.setParameters((NameValueList) rr.getParameters()
904: .clone());
905: routeList.add(route);
906: }
907:
908: RouteHeader firstRoute = (RouteHeader) routeList.getFirst();
909:
910: if (!((SipURI) firstRoute.getAddress().getURI())
911: .hasLrParam()) {
912: RouteHeader route = new RouteHeader();
913: route
914: .setAddress((Address) contact.getAddress()
915: .clone());
916: routeList.removeFirst();
917: // IMPL_NOTE: is clone() need?
918: URI uri = firstRoute.getAddress().getURI();
919: request.setRequestURI(uri);
920: routeList.add(route);
921: request.addHeader(routeList);
922: } else {
923: URI uri = (URI) contact.getAddress().getURI().clone();
924: request.setRequestURI(uri);
925: request.addHeader(routeList);
926: }
927: }
928: }
929: }
|