1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip;
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.*;
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.stack.*;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.*;
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.*;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.*;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.ThreadAuditor;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/* bug fixes SIPQuest communications and Shu-Lin Chen. */
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Event Scanner to deliver events to the Listener.
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.41 $ $Date: 2009/11/18 02:35:17 $
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangclass EventScanner implements Runnable {
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean isStopped;
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int refCount;
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // SIPquest: Fix for deadlocks
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private LinkedList pendingEvents = new LinkedList();
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int[] eventMutex = { 0 };
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private SipStackImpl sipStack;
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void incrementRefcount() {
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (eventMutex) {
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.refCount++;
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public EventScanner(SipStackImpl sipStackImpl) {
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.pendingEvents = new LinkedList();
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Thread myThread = new Thread(this);
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // This needs to be set to false else the
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // main thread mysteriously exits.
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myThread.setDaemon(false);
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipStack = sipStackImpl;
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myThread.setName("EventScannerThread");
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        myThread.start();
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void addEvent(EventWrapper eventWrapper) {
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	if (sipStack.isLoggingEnabled())
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    		sipStack.getStackLogger().logDebug("addEvent " + eventWrapper);
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.eventMutex) {
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            pendingEvents.add(eventWrapper);
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Add the event into the pending events list
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            eventMutex.notify();
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Stop the event scanner. Decrement the reference count and exit the
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * scanner thread if the ref count goes to 0.
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void stop() {
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (eventMutex) {
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.refCount > 0)
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.refCount--;
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.refCount == 0) {
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                isStopped = true;
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                eventMutex.notify();
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Brutally stop the event scanner. This does not wait for the refcount to
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * go to 0.
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void forceStop() {
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.eventMutex) {
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.isStopped = true;
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.refCount = 0;
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.eventMutex.notify();
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void deliverEvent(EventWrapper eventWrapper) {
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        EventObject sipEvent = eventWrapper.sipEvent;
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipStack.isLoggingEnabled())
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logDebug(
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "sipEvent = " + sipEvent + "source = "
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            + sipEvent.getSource());
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SipListener sipListener = null;
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!(sipEvent instanceof IOExceptionEvent)) {
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipListener = ((SipProviderImpl) sipEvent.getSource()).getSipListener();
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipListener = sipStack.getSipListener();
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipEvent instanceof RequestEvent) {
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Check if this request has already created a
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // transaction
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPRequest sipRequest = (SIPRequest) ((RequestEvent) sipEvent)
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getRequest();
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "deliverEvent : "
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + sipRequest.getFirstLine()
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + " transaction "
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + eventWrapper.transaction
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + " sipEvent.serverTx = "
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + ((RequestEvent) sipEvent)
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            .getServerTransaction());
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Discard the duplicate request if a
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // transaction already exists. If the listener chose
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // to handle the request statelessly, then the listener
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // will see the retransmission.
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Note that in both of these two cases, JAIN SIP will allow
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // you to handle the request statefully or statelessly.
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // An example of the latter case is REGISTER and an example
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // of the former case is INVITE.
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPServerTransaction tx = (SIPServerTransaction) sipStack
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .findTransaction(sipRequest, true);
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (tx != null && !tx.passToListener()) {
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // JvB: make an exception for a very rare case: some
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // (broken) UACs use
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // the same branch parameter for an ACK. Such an ACK should
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // be passed
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // to the listener (tx == INVITE ST, terminated upon sending
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // 2xx but
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // lingering to catch retransmitted INVITEs)
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipRequest.getMethod().equals(Request.ACK)
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && tx.isInviteTransaction() &&
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            ( tx.getLastResponse().getStatusCode()/100 == 2 ||
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                sipStack.isNon2XXAckPassedToListener())) {
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled())
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    .getStackLogger()
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    .logDebug(
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            "Detected broken client sending ACK with same branch! Passing...");
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } else {
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled())
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug(
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    "transaction already exists! " + tx);
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return;
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else if (sipStack.findPendingTransaction(sipRequest) != null) {
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled())
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "transaction already exists!!");
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return;
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Put it in the pending list so that if a repeat
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // request comes along it will not get assigned a
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // new transaction
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    SIPServerTransaction st = (SIPServerTransaction) eventWrapper.transaction;
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.putPendingTransaction(st);
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Set up a pointer to the transaction.
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipRequest.setTransaction(eventWrapper.transaction);
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Change made by SIPquest
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger()
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .logDebug(
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        "Calling listener "
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                                + sipRequest.getFirstLine());
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Calling listener " + eventWrapper.transaction);
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipListener != null)
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipListener.processRequest((RequestEvent) sipEvent);
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Done processing Message "
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        + sipRequest.getFirstLine());
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (eventWrapper.transaction != null) {
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        SIPDialog dialog = (SIPDialog) eventWrapper.transaction
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .getDialog();
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (dialog != null)
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            dialog.requestConsumed();
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (Exception ex) {
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // We cannot let this thread die under any
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // circumstances. Protect ourselves by logging
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // errors to the console but continue.
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logException(ex);
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } finally {
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "Done processing Message "
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + ((SIPRequest) (((RequestEvent) sipEvent)
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            .getRequest())).getFirstLine());
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (eventWrapper.transaction != null
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && ((SIPServerTransaction) eventWrapper.transaction)
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .passToListener()) {
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((SIPServerTransaction) eventWrapper.transaction)
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .releaseSem();
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (eventWrapper.transaction != null)
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .removePendingTransaction((SIPServerTransaction) eventWrapper.transaction);
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (eventWrapper.transaction.getOriginalRequest().getMethod()
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .equals(Request.ACK)) {
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Set the tx state to terminated so it is removed from the
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // stack
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // if the user configured to get notification on ACK
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // termination
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    eventWrapper.transaction
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .setState(TransactionState.TERMINATED);
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (sipEvent instanceof ResponseEvent) {
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ResponseEvent responseEvent = (ResponseEvent) sipEvent;
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPResponse sipResponse = (SIPResponse) responseEvent
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getResponse();
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPDialog sipDialog = ((SIPDialog) responseEvent.getDialog());
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Calling listener for "
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        + sipResponse.getFirstLine());
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipListener != null) {
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        SIPTransaction tx = eventWrapper.transaction;
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (tx != null) {
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            tx.setPassToListener();
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipListener.processResponse((ResponseEvent) sipEvent);
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    /*
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * If the response for a request within a dialog is a 481
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * (Call/Transaction Does Not Exist) or a 408 (Request
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * Timeout), the UAC SHOULD terminate the dialog.
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     */
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if ((sipDialog != null && (sipDialog.getState() == null || !sipDialog
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .getState().equals(DialogState.TERMINATED)))
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && (sipResponse.getStatusCode() == Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST || sipResponse
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    .getStatusCode() == Response.REQUEST_TIMEOUT)) {
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled()) {
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug(
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    "Removing dialog on 408 or 481 response");
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipDialog.doDeferredDelete();
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    /*
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * The Client tx disappears after the first 2xx response
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * However, additional 2xx responses may arrive later for
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * example in the following scenario:
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     *
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * Multiple 2xx responses may arrive at the UAC for a single
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * INVITE request due to a forking proxy. Each response is
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * distinguished by the tag parameter in the To header
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * field, and each represents a distinct dialog, with a
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * distinct dialog identifier.
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     *
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * If the Listener does not ACK the 200 then we assume he
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * does not care about the dialog and gc the dialog after
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * some time. However, this is really an application bug.
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     * This garbage collects unacknowledged dialogs.
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     *
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     */
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipResponse.getCSeq().getMethod()
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .equals(Request.INVITE)
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && sipDialog != null
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            && sipResponse.getStatusCode() == 200) {
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled()) {
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logDebug(
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    "Warning! unacknowledged dialog. " + sipDialog.getState());
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        /*
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                         * If we dont see an ACK in 32 seconds, we want to tear down the dialog.
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                         */
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipDialog.doDeferredDeleteIfNoAckSent(sipResponse.getCSeq().getSeqNumber());
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (Exception ex) {
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // We cannot let this thread die under any
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // circumstances. Protect ourselves by logging
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // errors to the console but continue.
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logException(ex);
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // The original request is not needed except for INVITE
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // transactions -- null the pointers to the transactions so
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // that state may be released.
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPClientTransaction ct = (SIPClientTransaction) eventWrapper.transaction;
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (ct != null
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && TransactionState.COMPLETED == ct.getState()
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && ct.getOriginalRequest() != null
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && !ct.getOriginalRequest().getMethod().equals(
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                Request.INVITE)) {
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // reduce the state to minimum
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // This assumes that the application will not need
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // to access the request once the transaction is
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // completed.
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ct.clearState();
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // mark no longer in the event queue.
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } finally {
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (eventWrapper.transaction != null
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        && eventWrapper.transaction.passToListener()) {
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    eventWrapper.transaction.releaseSem();
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (sipEvent instanceof TimeoutEvent) {
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Change made by SIPquest
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Check for null as listener could be removed.
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipListener != null)
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipListener.processTimeout((TimeoutEvent) sipEvent);
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // We cannot let this thread die under any
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // circumstances. Protect ourselves by logging
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // errors to the console but continue.
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logException(ex);
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (sipEvent instanceof DialogTimeoutEvent) {
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Check for null as listener could be removed.
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipListener != null && sipListener instanceof SipListenerExt) {
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((SipListenerExt)sipListener).processDialogTimeout((DialogTimeoutEvent) sipEvent);
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // We cannot let this thread die under any
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // circumstances. Protect ourselves by logging
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // errors to the console but continue.
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logException(ex);
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (sipEvent instanceof IOExceptionEvent) {
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipListener != null)
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipListener.processIOException((IOExceptionEvent) sipEvent);
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logException(ex);
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (sipEvent instanceof TransactionTerminatedEvent) {
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipStack.isLoggingEnabled()) {
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "About to deliver transactionTerminatedEvent");
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "tx = "
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + ((TransactionTerminatedEvent) sipEvent)
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            .getClientTransaction());
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logDebug(
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            "tx = "
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    + ((TransactionTerminatedEvent) sipEvent)
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                            .getServerTransaction());
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipListener != null)
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipListener
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .processTransactionTerminated((TransactionTerminatedEvent) sipEvent);
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (AbstractMethodError ame) {
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // JvB: for backwards compatibility, accept this
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            	if (sipStack.isLoggingEnabled())
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            		sipStack
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .getStackLogger()
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .logWarning(
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Unable to call sipListener.processTransactionTerminated");
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logException(ex);
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (sipEvent instanceof DialogTerminatedEvent) {
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipListener != null)
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipListener
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .processDialogTerminated((DialogTerminatedEvent) sipEvent);
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (AbstractMethodError ame) {
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // JvB: for backwards compatibility, accept this
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            	if (sipStack.isLoggingEnabled())
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            		sipStack.getStackLogger().logWarning(
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        "Unable to call sipListener.processDialogTerminated");
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipStack.getStackLogger().logException(ex);
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sipStack.getStackLogger().logFatalError("bad event" + sipEvent);
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * For the non-re-entrant listener this delivers the events to the listener
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * from a single queue. If the listener is re-entrant, then the stack just
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * calls the deliverEvent method above.
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void run() {
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Ask the auditor to monitor this thread
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ThreadAuditor.ThreadHandle threadHandle = sipStack.getThreadAuditor().addCurrentThread();
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (true) {
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                EventWrapper eventWrapper = null;
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                LinkedList eventsToDeliver;
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                synchronized (this.eventMutex) {
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // First, wait for some events to become available.
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    while (pendingEvents.isEmpty()) {
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // There's nothing in the list, check to make sure we
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // haven't
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // been stopped. If we have, then let the thread die.
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (this.isStopped) {
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            if (sipStack.isLoggingEnabled())
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                sipStack.getStackLogger().logDebug(
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        "Stopped event scanner!!");
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            return;
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // We haven't been stopped, and the event list is indeed
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // rather empty. Wait for some events to come along.
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        try {
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // Send a heartbeat to the thread auditor
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            threadHandle.ping();
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // Wait for events (with a timeout)
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            eventMutex.wait(threadHandle.getPingIntervalInMillisecs());
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        } catch (InterruptedException ex) {
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            // Let the thread die a normal death
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        	if (sipStack.isLoggingEnabled())
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        		sipStack.getStackLogger().logDebug("Interrupted!");
490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            return;
491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // There are events in the 'pending events list' that need
495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // processing. Hold onto the old 'pending Events' list, but
496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // make a new one for the other methods to operate on. This
497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // tap-dancing is to avoid deadlocks and also to ensure that
498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // the list is not modified while we are iterating over it.
499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    eventsToDeliver = pendingEvents;
500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    pendingEvents = new LinkedList();
501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ListIterator iterator = eventsToDeliver.listIterator();
503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (iterator.hasNext()) {
504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    eventWrapper = (EventWrapper) iterator.next();
505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipStack.isLoggingEnabled()) {
506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        sipStack.getStackLogger().logDebug(
507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "Processing " + eventWrapper + "nevents "
508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        + eventsToDeliver.size());
509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        deliverEvent(eventWrapper);
512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (Exception e) {
513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (sipStack.isLoggingEnabled()) {
514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            sipStack.getStackLogger().logError(
515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                    "Unexpected exception caught while delivering event -- carrying on bravely", e);
516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } // end While
520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipStack.isLoggingEnabled()) {
522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!this.isStopped) {
523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipStack.getStackLogger().logFatalError("Event scanner exited abnormally");
524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
530