001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package gov.nist.microedition.sip;
028:
029: import javax.microedition.sip.*;
030: import javax.microedition.io.Connector;
031: import gov.nist.siplite.message.Request;
032: import gov.nist.siplite.message.Response;
033: import gov.nist.siplite.address.Address;
034: import gov.nist.siplite.address.SipURI;
035: import gov.nist.siplite.header.ToHeader;
036: import gov.nist.siplite.header.ContactHeader;
037: import gov.nist.siplite.stack.ClientTransaction;
038: import gov.nist.siplite.SipStack;
039: import gov.nist.siplite.stack.SIPServerResponseInterface;
040: import gov.nist.siplite.stack.GetSipServerResponse;
041: import gov.nist.core.ParseException;
042: import gov.nist.siplite.header.ExpiresHeader;
043: import com.sun.midp.i3test.TestCase;
044:
045: /**
046: * Tests for SipConnection class.
047: *
048: */
049: public class TestSipDialogClient extends TestCase {
050:
051: /** URI of other side of SIP session. */
052: private String corrURI = "sip:sippy.tester@localhost:5060";
053:
054: /** Refresh ID for refreshable requests. */
055: private int refreshID = 0;
056:
057: /** Server tag. */
058: private static final String toTag = StackConnector.generateTag();
059:
060: /**
061: * Body of the test 1.
062: *
063: * INVITE request - walk along states of SipDialog object.
064: * @param transport the name of transport protocol
065: */
066: void Test1(String transport) {
067: /** Client connection. */
068: SipClientConnection sc = null;
069: StubSipRefreshListener refreshListener = null;
070:
071: // create a dialog
072: try {
073: // Open SIP client connection to the local SIP server
074: sc = (SipClientConnection) Connector.open(corrURI
075: + ";transport=" + transport);
076: } catch (Exception ex) {
077: assertNull("Exception during sc open", sc);
078: }
079:
080: // Dialog instance is not visible (no provisional respomse)
081: // (JSR180, 1.0.1, p. 42)
082: assertTrue("Dialog is visible on initialization", sc
083: .getDialog() == null);
084:
085: // Move to EARLY state
086: try {
087: sc.initRequest("INVITE", null);
088: refreshListener = new StubSipRefreshListener();
089: refreshID = sc.enableRefresh(refreshListener);
090: sc.send(); // send a message
091: // Receiving provisional response
092: sendResponse(sc, Response.TRYING);
093: } catch (Exception ex) {
094: fail("Exception during moving to EARLY state");
095: }
096:
097: // dialog must be visible
098: SipDialog testDialog = sc.getDialog();
099: assertTrue("Dialog is null", testDialog != null);
100: // dialog must be in EARLY state
101: assertTrue("Dialog instance has wrong state", testDialog
102: .getState() == SipDialog.EARLY);
103:
104: // Move to CONFIRMED state
105: sendResponse(sc, Response.OK);
106: // dialog must be visible
107: testDialog = sc.getDialog();
108: assertTrue("Dialog is null", testDialog != null);
109: // dialog must be in CONFIRMED state
110: assertTrue("Dialog instance has wrong state", testDialog
111: .getState() == SipDialog.CONFIRMED);
112:
113: // close the connection
114: try {
115: sc.close();
116: } catch (Exception ex) {
117: fail("Exception during closing SipClientConnection");
118: }
119:
120: // Send a message inside dialog
121: SipClientConnection scl = null;
122: try {
123: scl = testDialog.getNewClientConnection("MESSAGE");
124: scl.send();
125: sendResponse(scl, Response.MULTIPLE_CHOICES);
126: } catch (Exception ex) {
127: fail("Exception during sending request inside a dialog");
128: ex.printStackTrace();
129: }
130: // dialog must be in CONFIRMED state
131: assertTrue("Dialog instance has wrong state", testDialog
132: .getState() == SipDialog.CONFIRMED);
133:
134: // close the connection
135: try {
136: scl.close();
137: } catch (Exception ex) {
138: fail("Exception during closing SipClientConnection");
139: }
140:
141: // Move to TERMINATED state
142: try {
143: scl = testDialog.getNewClientConnection("BYE");
144: scl.send();
145: sendResponse(scl, Response.OK);
146: } catch (Exception ex) {
147: fail("Exception during moving to TERMINATED state");
148: ex.printStackTrace();
149: }
150: // dialog must not be visible - see JSR180, method getDialog
151: testDialog = scl.getDialog();
152: assertTrue("Dialog is not null", testDialog == null);
153:
154: // close the connection
155: try {
156: scl.close();
157: } catch (Exception ex) {
158: fail("Exception during closing SipClientConnection");
159: }
160:
161: }
162:
163: /**
164: * Body of the test 2.
165: *
166: * SUBSCRIBE request - walk along states of SipDialog object.
167: * @param transport the name of transport protocol
168: */
169: void Test2(String transport) {
170: /** Client connection. */
171: SipClientConnection sc = null;
172: StubSipRefreshListener refreshListener = null;
173:
174: // create a dialog
175: try {
176: // Open SIP client connection to the local SIP server
177: sc = (SipClientConnection) Connector
178: .open("sip:sippy.tester@localhost:5060;transport="
179: + transport);
180: } catch (Exception ex) {
181: assertNull("Exception during sc open", sc);
182: }
183:
184: // Dialog instance is not visible (no response)
185: // (JSR180, 1.0.1, p. 42)
186: assertTrue("Dialog is visible on initialization", sc
187: .getDialog() == null);
188:
189: // Move to EARLY state
190: try {
191: sc.initRequest("SUBSCRIBE", null);
192: refreshListener = new StubSipRefreshListener();
193: refreshID = sc.enableRefresh(refreshListener);
194: // SUBSCRIBE request - Event header is mandatory (RFC 3265, 7.2)
195: sc.setHeader("Event", "12345");
196: sc.send(); // send a message
197: sendResponse(sc, Response.TRYING);
198: } catch (Exception ex) {
199: fail("Exception during moving to EARLY state");
200: }
201:
202: // dialog must be unvisible even after provisional response
203: // (SUBSCRIBE dialog)
204: assertTrue("Dialog is not visible", sc.getDialog() != null);
205: assertTrue("Dialog instance has wrong state", sc.getDialog()
206: .getState() == SipDialog.EARLY);
207:
208: // Move to CONFIRMED state
209: sendResponse(sc, Response.OK);
210: // dialog must be visible
211: SipDialog testDialog = sc.getDialog();
212: assertTrue("Dialog is null", testDialog != null);
213: // dialog must be in CONFIRMED state
214: assertTrue("Dialog instance has wrong state", testDialog
215: .getState() == SipDialog.CONFIRMED);
216:
217: // close the connection
218: try {
219: sc.close();
220: } catch (Exception ex) {
221: fail("Exception during closing SipClientConnection");
222: }
223:
224: // Send a message inside dialog
225: SipClientConnection scl = null;
226: try {
227: scl = testDialog.getNewClientConnection("MESSAGE");
228: scl.send();
229: sendResponse(scl, Response.MULTIPLE_CHOICES);
230: } catch (Exception ex) {
231: fail("Exception during sending request inside a dialog");
232: ex.printStackTrace();
233: }
234: // dialog must be in CONFIRMED state
235: assertTrue("Dialog instance has wrong state", testDialog
236: .getState() == SipDialog.CONFIRMED);
237:
238: // close the connection
239: try {
240: scl.close();
241: } catch (Exception ex) {
242: fail("Exception during closing SipClientConnection");
243: }
244:
245: // Move to TERMINATED state
246: try {
247: scl = testDialog.getNewClientConnection("SUBSCRIBE");
248: scl.setHeader("Event", "12345");
249: // unsubscribe
250: scl.setHeader("Expires", "0");
251: scl.send();
252: sendResponse(scl, Response.OK);
253: } catch (Exception ex) {
254: fail("Exception during moving to TERMINATED state");
255: ex.printStackTrace();
256: }
257: // dialog must not be visible - see JSR180, method getDialog
258: testDialog = scl.getDialog();
259: assertTrue("Dialog is not null", testDialog == null);
260:
261: // close the connection
262: try {
263: scl.close();
264: } catch (Exception ex) {
265: fail("Exception during closing SipClientConnection");
266: }
267: }
268:
269: /**
270: * Send a response with given code.
271: *
272: * @param sc SipClientConnection object
273: * @param respCode response code
274: */
275: private void sendResponse(SipClientConnection sc, int respCode) {
276:
277: // Send a response
278: Request request = null;
279: Response response = null;
280:
281: try {
282: request = ((SipClientConnectionImpl) sc).getRequest();
283: // create a response for request
284: response = request.createResponse(respCode);
285:
286: // When response is 200 OK change "To" header (RFC 3261, 17.1.1.3)
287: if (respCode == Response.OK) {
288: Address toAddress = StackConnector.addressFactory
289: .createAddress(corrURI);
290: ToHeader toHeader = null;
291: try {
292: toHeader = StackConnector.headerFactory
293: .createToHeader(toAddress, null);
294: } catch (ParseException ex) {
295: fail("Problem during the creation"
296: + " of the ToHeader");
297: }
298: response.setTo(toHeader);
299: }
300:
301: // When response is 2xx and request is refreshable,
302: // response must contain "expires" header (RFC 3265, 7.1)
303: if ((respCode / 100 == 2) && (refreshID != 0)
304: && (response.getHeader("Expires") == null)) {
305: ExpiresHeader expHeader = new ExpiresHeader();
306: expHeader.setExpires(1000);
307: response.setHeader(expHeader);
308: }
309:
310: // RFC 3261 8.2.6.2 Response must have To tag
311: ToHeader toHeader = response.getTo();
312: if (!toHeader.hasTag()) {
313: // To header has no tag - add server tag
314: toHeader.setTag(toTag);
315: response.setTo(toHeader);
316: }
317:
318: // add Contact header when request is not "MESSAGE"
319: if ((respCode == Response.OK)
320: && (!request.getMethod().equals("MESSAGE"))) {
321: SipURI contactURI = StackConnector.addressFactory
322: .createSipURI("sippy.tester", // name
323: "localhost:5060");
324: ContactHeader contactHeader = StackConnector.headerFactory
325: .createContactHeader(StackConnector.addressFactory
326: .createAddress(contactURI));
327: response.addHeader(contactHeader);
328: }
329:
330: ClientTransaction clientTransaction = ((SipClientConnectionImpl) sc)
331: .getClientTransaction();
332:
333: SipStack sipStack = ((SipClientConnectionImpl) sc)
334: .getSipStack();
335:
336: SIPServerResponseInterface ssc = GetSipServerResponse
337: .newSIPServerResponse(sipStack, response,
338: clientTransaction.getMessageChannel());
339:
340: ssc.processResponse(response, clientTransaction
341: .getMessageChannel());
342: // receive a response
343: assertTrue("Response wasn't received", sc.receive(10000));
344: } catch (Throwable e) {
345: fail("sendResponse " + e + " was caused");
346: e.printStackTrace();
347: }
348: }
349:
350: /**
351: * Tests execute
352: *
353: */
354: public void runTests() {
355: String arrProt[] = { "UDP", "TCP" };
356: for (int i = 0; i < arrProt.length; i++) {
357: declare("SipDialog - INVITE " + arrProt[i]);
358: Test1(arrProt[i]);
359: declare("SipDialog - SUBSCRIBE " + arrProt[i]);
360: Test2(arrProt[i]);
361: }
362: }
363:
364: }
|