001: package examples.nistgoodies.leakaudit;
002:
003: import gov.nist.javax.sip.stack.SIPDialog;
004: import gov.nist.javax.sip.stack.SIPClientTransaction;
005: import gov.nist.javax.sip.SipStackImpl;
006:
007: import javax.sip.*;
008: import javax.sip.address.Address;
009: import javax.sip.address.SipURI;
010: import javax.sip.address.AddressFactory;
011: import javax.sip.header.*;
012: import javax.sip.message.Request;
013: import javax.sip.message.Response;
014: import javax.sip.message.MessageFactory;
015: import java.util.*;
016: import java.text.ParseException;
017:
018: /**
019: * This example demonstrates how an application can monitor the SIP Stack
020: * for leaked dialogs and transactions.
021: * <p/>
022: * This code is in the public domain.
023: *
024: * @author R. Borba (Natural Convergence)
025: */
026: public class LeakingApp implements SipListener {
027:
028: /// Dialogs indexed by call id
029: private Map dialogs = new HashMap();
030:
031: /// Current CSeq
032: private long cseq = 0;
033:
034: /// Stack objects
035: private HeaderFactory headerFactory;
036: private MessageFactory messageFactory;
037: private AddressFactory addressFactory;
038: private AllowHeader ALLOW;
039:
040: /// Constructor
041: public LeakingApp() {
042: SipFactory l_oSipFactory = SipFactory.getInstance();
043: try {
044: headerFactory = l_oSipFactory.createHeaderFactory();
045: messageFactory = l_oSipFactory.createMessageFactory();
046: addressFactory = l_oSipFactory.createAddressFactory();
047: ALLOW = headerFactory.createAllowHeader(Request.REGISTER
048: + ',' + Request.INVITE + ',' + Request.CANCEL + ','
049: + Request.ACK + ',' + Request.BYE + ','
050: + Request.REFER + ',' + Request.INFO);
051: } catch (Exception e) {
052: System.out
053: .println("LeakingApp: Error creating stack objects. Exception: "
054: + e.toString());
055: }
056: }
057:
058: // ---------------------
059: // SipListener interface
060: // ---------------------
061:
062: public void processRequest(RequestEvent a_oEvent) {
063: Request l_oRequest = a_oEvent.getRequest();
064: String l_sCallID = ((CallIdHeader) l_oRequest
065: .getHeader(CallIdHeader.NAME)).getCallId();
066: System.out.println("processRequest(): CallID=" + l_sCallID
067: + ", Request= " + l_oRequest.getMethod());
068: }
069:
070: public void processResponse(ResponseEvent a_oEvent) {
071: Response l_oResponse = a_oEvent.getResponse();
072: String l_sCallID = ((CallIdHeader) l_oResponse
073: .getHeader(CallIdHeader.NAME)).getCallId();
074: System.out.println("processResponse(): CallID=" + l_sCallID
075: + ", Response= " + l_oResponse.toString());
076: }
077:
078: public void processTimeout(TimeoutEvent a_oEvent) {
079: System.out.println("processTimeout()");
080: }
081:
082: public void processIOException(IOExceptionEvent exceptionEvent) {
083: System.out.println("IOExceptionEvent: "
084: + exceptionEvent.toString());
085: }
086:
087: public void processTransactionTerminated(
088: TransactionTerminatedEvent transactionTerminatedEvent) {
089: System.out.println("TransactionTerminatedEvent: "
090: + transactionTerminatedEvent.toString());
091: }
092:
093: public void processDialogTerminated(
094: DialogTerminatedEvent dialogTerminatedEvent) {
095: System.out.println("DialogTerminatedEvent: "
096: + dialogTerminatedEvent.toString());
097: }
098:
099: /// Creates a request containing an INVITE message
100: private Request createRequest() {
101: try {
102: CallIdHeader callIdHeader = LeakAudit.sipProvider
103: .getNewCallId();
104: CSeqHeader cseqHeader = headerFactory.createCSeqHeader(
105: ++cseq, Request.INVITE);
106: SipURI requestURI = addressFactory.createSipURI("to-user",
107: "127.0.0.1");
108: requestURI.setTransportParam("udp");
109:
110: SipURI fromURI = addressFactory.createSipURI("from-user",
111: LeakAudit.sipStack.getIPAddress());
112: Address fromAddress = addressFactory.createAddress(
113: "from-user", fromURI);
114: String fromTag = String
115: .valueOf((int) (Math.random() * 10000));
116: FromHeader fromHeader = headerFactory.createFromHeader(
117: fromAddress, fromTag);
118:
119: SipURI toURI = addressFactory.createSipURI("to-user",
120: "127.0.0.1");
121: Address toAddress = addressFactory.createAddress("to-user",
122: toURI);
123: String toTag = String
124: .valueOf((int) (Math.random() * 10000));
125: ToHeader toHeader = headerFactory.createToHeader(toAddress,
126: toTag);
127:
128: ListeningPoint listeningPoint = LeakAudit.sipProvider
129: .getListeningPoints()[0];
130: ViaHeader viaHeader = headerFactory.createViaHeader(
131: LeakAudit.sipStack.getIPAddress(), listeningPoint
132: .getPort(), listeningPoint.getTransport(),
133: null);
134:
135: // add via headers
136: ArrayList viaList = new ArrayList();
137: viaList.add(viaHeader);
138:
139: MaxForwardsHeader maxForwards = headerFactory
140: .createMaxForwardsHeader(70);
141:
142: Request request = messageFactory.createRequest(requestURI,
143: Request.INVITE, callIdHeader, cseqHeader,
144: fromHeader, toHeader, viaList, maxForwards);
145:
146: // Add the Contact header
147: SipURI sipUri = addressFactory.createSipURI(null,
148: LeakAudit.sipStack.getIPAddress());
149: Address contactAddress = addressFactory
150: .createAddress(sipUri);
151: ContactHeader contactHeader = headerFactory
152: .createContactHeader(contactAddress);
153: request.addHeader(contactHeader);
154:
155: // Add Allow headers
156: request.addHeader(ALLOW);
157:
158: return request;
159: } catch (ParseException e) {
160: System.err.println("ParseException " + e.getMessage());
161: } catch (InvalidArgumentException e) {
162: System.err.println("InvalidArgumentException "
163: + e.getMessage());
164: } catch (Exception e) {
165: System.err.println("Exception " + e.getMessage());
166: }
167: return null;
168: }
169:
170: // Creates a transaction for this request
171: private ClientTransaction createTransaction(Request request) {
172: try {
173: return LeakAudit.sipProvider
174: .getNewClientTransaction(request);
175: } catch (Exception e) {
176: System.err.println("Exception " + e.getMessage());
177: }
178: return null;
179: }
180:
181: /// Sends an INVITE request to a dummy location
182: public void sendRequest() {
183: try {
184: // Create the request and the transaction
185: Request request = createRequest();
186: ClientTransaction transaction = createTransaction(request);
187:
188: // Send the request
189: // System.out.println("Sending Request: " + request.toString());
190: transaction.sendRequest();
191:
192: // Remember this call id and this transaction
193: CallIdHeader callIdHeader = (CallIdHeader) request
194: .getHeader(CallIdHeader.NAME);
195: dialogs.put(callIdHeader.getCallId(), transaction);
196:
197: System.out.println("Sent INVITE, Call ID = "
198: + callIdHeader.getCallId());
199: } catch (Exception e) {
200: System.err.println("Exception " + e.getMessage());
201: }
202: }
203:
204: /// Leaks a dialog into the stack
205: public void leakDialog() {
206: // Insert a foreign dialog from nowhere just so we can detect it
207: // Note: Normally we would ask the application to "forget" about one of its call ids by removing one of
208: // the entries in the "dialogs" hashmap". However, the stack only creates a dialog for a client transaction
209: // *after* the client transaction gets a response. Since our little example is not getting any response for
210: // its INVITEs (there's nobody there to respond), removing a dialog from its hashmap doesn't have any effect
211: // on this test. So, we have to do it the hard way, i.e., insert a fake dialog by force into the stack and
212: // wait until it is detected as leaked.
213: // You should see something like this at the console:
214: //
215: // Leaked dialogs:
216: // dialog id: 1234, dialog state: null
217: // Total: 1 leaked dialogs detected and removed.
218: //
219: // Also notice that leaked transactions are a little harder to simulate so I'm not even trying in this example.
220: Request request = createRequest();
221: SIPClientTransaction transaction = (SIPClientTransaction) createTransaction(request);
222: SIPDialog dialog = ((SipStackImpl) LeakAudit.sipStack)
223: .createDialog(transaction);
224: dialog.setDialogId("1234");
225: ((SipStackImpl) LeakAudit.sipStack).putDialog(dialog);
226: System.out
227: .println("Intentionally inserted a leaked dialog, CallID = "
228: + dialog.getCallId());
229: }
230:
231: /// Returns a list (set) of active call IDs used by this application
232: public Set getActiveCallIDs() {
233: return dialogs.keySet();
234: }
235: }
|