001: /*
002: * Conditions Of Use
003: *
004: * This software was developed by employees of the National Institute of
005: * Standards and Technology (NIST), and others.
006: * This software is has been contributed to the public domain.
007: * As a result, a formal license is not needed to use the software.
008: *
009: * This software is provided "AS IS."
010: * NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
011: * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
012: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
013: * AND DATA ACCURACY. NIST does not warrant or make any representations
014: * regarding the use of the software or the results thereof, including but
015: * not limited to the correctness, accuracy, reliability or usefulness of
016: * the software.
017: *
018: *
019: */
020: package test.tck.msgflow.callflows.reinvite;
021:
022: import gov.nist.javax.sip.address.SipUri;
023:
024: import javax.sip.*;
025: import javax.sip.address.*;
026: import javax.sip.header.*;
027: import javax.sip.message.*;
028:
029: import org.apache.log4j.ConsoleAppender;
030: import org.apache.log4j.FileAppender;
031: import org.apache.log4j.Logger;
032: import org.apache.log4j.SimpleLayout;
033: import org.apache.log4j.helpers.NullEnumeration;
034:
035: import test.tck.TestHarness;
036: import test.tck.msgflow.callflows.ProtocolObjects;
037:
038: import java.util.*;
039:
040: import junit.framework.TestCase;
041:
042: /**
043: * This class is a UAC template.
044: *
045: * @author M. Ranganathan
046: */
047:
048: public class Shootist implements SipListener {
049:
050: private SipProvider provider;
051:
052: private int reInviteCount;
053:
054: private ContactHeader contactHeader;
055:
056: private ListeningPoint listeningPoint;
057:
058: private int counter;
059:
060: private static String PEER_ADDRESS = Shootme.myAddress;
061:
062: private static int PEER_PORT = Shootme.myPort;
063:
064: private static String peerHostPort = PEER_ADDRESS + ":" + PEER_PORT;
065:
066: // To run on two machines change these to suit.
067: public static final String myAddress = "127.0.0.1";
068:
069: private static final int myPort = 5060;
070:
071: protected ClientTransaction inviteTid;
072:
073: private boolean okReceived;
074:
075: private boolean byeOkRecieved;
076:
077: private boolean byeSent;
078:
079: int reInviteReceivedCount;
080:
081: private static Logger logger = Logger.getLogger(Shootist.class);
082:
083: static {
084: if (logger.getAllAppenders().equals(
085: NullEnumeration.getInstance())) {
086:
087: logger.addAppender(new ConsoleAppender(new SimpleLayout()));
088:
089: }
090: }
091:
092: private ProtocolObjects protocolObjects;
093:
094: private Dialog dialog;
095:
096: public Shootist(ProtocolObjects protocolObjects) {
097: super ();
098: this .protocolObjects = protocolObjects;
099:
100: }
101:
102: public void processRequest(RequestEvent requestReceivedEvent) {
103: Request request = requestReceivedEvent.getRequest();
104: ServerTransaction serverTransactionId = requestReceivedEvent
105: .getServerTransaction();
106:
107: logger.info("\n\nRequest " + request.getMethod()
108: + " received at "
109: + protocolObjects.sipStack.getStackName()
110: + " with server transaction id " + serverTransactionId);
111:
112: if (request.getMethod().equals(Request.BYE))
113: processBye(request, serverTransactionId);
114: else if (request.getMethod().equals(Request.INVITE))
115: processInvite(request, serverTransactionId);
116: else if (request.getMethod().equals(Request.ACK))
117: processAck(request, serverTransactionId);
118:
119: }
120:
121: public void processInvite(Request request, ServerTransaction st) {
122: try {
123: this .reInviteReceivedCount++;
124: Dialog dialog = st.getDialog();
125: Response response = protocolObjects.messageFactory
126: .createResponse(Response.OK, request);
127: ((ToHeader) response.getHeader(ToHeader.NAME))
128: .setTag(((ToHeader) request
129: .getHeader(ToHeader.NAME)).getTag());
130:
131: Address address = protocolObjects.addressFactory
132: .createAddress("Shootme <sip:" + myAddress + ":"
133: + myPort + ">");
134: ContactHeader contactHeader = protocolObjects.headerFactory
135: .createContactHeader(address);
136: response.addHeader(contactHeader);
137: st.sendResponse(response);
138: ReInviteTest.assertEquals(
139: "Dialog for reinvite must match original dialog",
140: dialog, this .dialog);
141: } catch (Exception ex) {
142: logger.error("unexpected exception", ex);
143: ReInviteTest.fail("unexpected exception");
144: }
145: }
146:
147: public void processAck(Request request, ServerTransaction tid) {
148: try {
149: logger.info("Got an ACK! sending bye : " + tid);
150: if (tid != null) {
151: Dialog dialog = tid.getDialog();
152: ReInviteTest.assertSame("dialog id mismatch", dialog,
153: this .dialog);
154: Request bye = dialog.createRequest(Request.BYE);
155: MaxForwardsHeader mf = protocolObjects.headerFactory
156: .createMaxForwardsHeader(10);
157: bye.addHeader(mf);
158: ClientTransaction ct = provider
159: .getNewClientTransaction(bye);
160: dialog.sendRequest(ct);
161: this .byeSent = true;
162: }
163: } catch (Exception ex) {
164: logger.error("unexpected exception", ex);
165: ReInviteTest.fail("unexpected exception");
166:
167: }
168: }
169:
170: public void processBye(Request request,
171: ServerTransaction serverTransactionId) {
172: try {
173: logger.info("shootist: got a bye .");
174: if (serverTransactionId == null) {
175: logger.info("shootist: null TID.");
176: return;
177: }
178: Dialog dialog = serverTransactionId.getDialog();
179: ReInviteTest.assertSame("dialog mismatch", dialog,
180: this .dialog);
181: logger.info("Dialog State = " + dialog.getState());
182: Response response = protocolObjects.messageFactory
183: .createResponse(200, request);
184: serverTransactionId.sendResponse(response);
185: logger.info("shootist: Sending OK.");
186: logger.info("Dialog State = " + dialog.getState());
187: ReInviteTest.assertEquals("Should be terminated", dialog
188: .getState(), DialogState.TERMINATED);
189:
190: } catch (Exception ex) {
191: logger.error("unexpected exception", ex);
192: ReInviteTest.fail("unexpected exception");
193:
194: }
195: }
196:
197: public void processResponse(ResponseEvent responseReceivedEvent) {
198: logger.info("Got a response");
199:
200: Response response = (Response) responseReceivedEvent
201: .getResponse();
202: Transaction tid = responseReceivedEvent.getClientTransaction();
203:
204: logger.info("Response received with client transaction id "
205: + tid + ":\n" + response.getStatusCode());
206: if (tid == null) {
207: logger.info("Stray response -- dropping ");
208: return;
209: }
210: logger.info("transaction state is " + tid.getState());
211: logger.info("Dialog = " + tid.getDialog());
212: logger.info("Dialog State is " + tid.getDialog().getState());
213: SipProvider provider = (SipProvider) responseReceivedEvent
214: .getSource();
215:
216: try {
217: if (response.getStatusCode() == Response.OK
218: && ((CSeqHeader) response
219: .getHeader(CSeqHeader.NAME)).getMethod()
220: .equals(Request.INVITE)) {
221:
222: // Request cancel = inviteTid.createCancel();
223: // ClientTransaction ct =
224: // sipProvider.getNewClientTransaction(cancel);
225: Dialog dialog = tid.getDialog();
226: CSeqHeader cseq = (CSeqHeader) response
227: .getHeader(CSeqHeader.NAME);
228: Request ackRequest = dialog.createAck(cseq
229: .getSeqNumber());
230: logger.info("Ack request to send = " + ackRequest);
231: logger.info("Sending ACK");
232: dialog.sendAck(ackRequest);
233:
234: // Send a Re INVITE but this time force it
235: // to use UDP as the transport. Else, it will
236: // Use whatever transport was used to create
237: // the dialog.
238: if (reInviteCount == 0) {
239: Request inviteRequest = dialog
240: .createRequest(Request.INVITE);
241: ((SipURI) inviteRequest.getRequestURI())
242: .removeParameter("transport");
243: ((ViaHeader) inviteRequest
244: .getHeader(ViaHeader.NAME))
245: .setTransport("udp");
246: inviteRequest.addHeader(contactHeader);
247: MaxForwardsHeader mf = protocolObjects.headerFactory
248: .createMaxForwardsHeader(10);
249: inviteRequest.addHeader(mf);
250: Thread.sleep(100);
251: ClientTransaction ct = provider
252: .getNewClientTransaction(inviteRequest);
253: dialog.sendRequest(ct);
254: reInviteCount++;
255: } else {
256: this .okReceived = true;
257: }
258:
259: } else if (response.getStatusCode() == Response.OK
260: && ((CSeqHeader) response
261: .getHeader(CSeqHeader.NAME)).getMethod()
262: .equals(Request.BYE)) {
263: this .byeOkRecieved = true;
264: }
265: } catch (Exception ex) {
266: ex.printStackTrace();
267:
268: logger.error(ex);
269: ReInviteTest.fail("unexpceted exception");
270: }
271:
272: }
273:
274: public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
275:
276: logger.info("Transaction Time out");
277: logger.info("TimeoutEvent " + timeoutEvent.getTimeout());
278: }
279:
280: public SipProvider createSipProvider() {
281: try {
282: listeningPoint = protocolObjects.sipStack
283: .createListeningPoint(myAddress, myPort,
284: protocolObjects.transport);
285:
286: provider = protocolObjects.sipStack
287: .createSipProvider(listeningPoint);
288: return provider;
289: } catch (Exception ex) {
290: logger.error(ex);
291: ReInviteTest.fail("unable to create provider");
292: return null;
293: }
294: }
295:
296: public void sendInvite() {
297:
298: try {
299:
300: // Note that a provider has multiple listening points.
301: // all the listening points must have the same IP address
302: // and port but differ in their transport parameters.
303:
304: String fromName = "BigGuy";
305: String fromSipAddress = "here.com";
306: String fromDisplayName = "The Master Blaster";
307:
308: String toSipAddress = "there.com";
309: String toUser = "LittleGuy";
310: String toDisplayName = "The Little Blister";
311:
312: // create >From Header
313: SipURI fromAddress = protocolObjects.addressFactory
314: .createSipURI(fromName, fromSipAddress);
315:
316: Address fromNameAddress = protocolObjects.addressFactory
317: .createAddress(fromAddress);
318: fromNameAddress.setDisplayName(fromDisplayName);
319: FromHeader fromHeader = protocolObjects.headerFactory
320: .createFromHeader(fromNameAddress, new Integer(
321: (int) (Math.random() * Integer.MAX_VALUE))
322: .toString());
323:
324: // create To Header
325: SipURI toAddress = protocolObjects.addressFactory
326: .createSipURI(toUser, toSipAddress);
327: Address toNameAddress = protocolObjects.addressFactory
328: .createAddress(toAddress);
329: toNameAddress.setDisplayName(toDisplayName);
330: ToHeader toHeader = protocolObjects.headerFactory
331: .createToHeader(toNameAddress, null);
332:
333: // create Request URI
334: SipURI requestURI = protocolObjects.addressFactory
335: .createSipURI(toUser, peerHostPort);
336:
337: // Create ViaHeaders
338:
339: ArrayList viaHeaders = new ArrayList();
340: int port = provider.getListeningPoint(
341: protocolObjects.transport).getPort();
342:
343: ViaHeader viaHeader = protocolObjects.headerFactory
344: .createViaHeader(myAddress, port,
345: protocolObjects.transport, null);
346:
347: // add via headers
348: viaHeaders.add(viaHeader);
349:
350: // Create ContentTypeHeader
351: ContentTypeHeader contentTypeHeader = protocolObjects.headerFactory
352: .createContentTypeHeader("application", "sdp");
353:
354: // Create a new CallId header
355: CallIdHeader callIdHeader = provider.getNewCallId();
356: // JvB: Make sure that the implementation matches the messagefactory
357: callIdHeader = protocolObjects.headerFactory
358: .createCallIdHeader(callIdHeader.getCallId());
359:
360: // Create a new Cseq header
361: CSeqHeader cSeqHeader = protocolObjects.headerFactory
362: .createCSeqHeader(1L, Request.INVITE);
363:
364: // Create a new MaxForwardsHeader
365: MaxForwardsHeader maxForwards = protocolObjects.headerFactory
366: .createMaxForwardsHeader(70);
367:
368: // Create the request.
369: Request request = protocolObjects.messageFactory
370: .createRequest(requestURI, Request.INVITE,
371: callIdHeader, cSeqHeader, fromHeader,
372: toHeader, viaHeaders, maxForwards);
373: // Create contact headers
374:
375: // Create the contact name address.
376: SipURI contactURI = protocolObjects.addressFactory
377: .createSipURI(fromName, myAddress);
378: contactURI.setPort(provider.getListeningPoint(
379: protocolObjects.transport).getPort());
380:
381: Address contactAddress = protocolObjects.addressFactory
382: .createAddress(contactURI);
383:
384: // Add the contact address.
385: contactAddress.setDisplayName(fromName);
386:
387: contactHeader = protocolObjects.headerFactory
388: .createContactHeader(contactAddress);
389: request.addHeader(contactHeader);
390:
391: // Add the extension header.
392: Header extensionHeader = protocolObjects.headerFactory
393: .createHeader("My-Header", "my header value");
394: request.addHeader(extensionHeader);
395:
396: String sdpData = "v=0\r\n"
397: + "o=4855 13760799956958020 13760799956958020"
398: + " IN IP4 129.6.55.78\r\n"
399: + "s=mysession session\r\n"
400: + "p=+46 8 52018010\r\n"
401: + "c=IN IP4 129.6.55.78\r\n" + "t=0 0\r\n"
402: + "m=audio 6022 RTP/AVP 0 4 18\r\n"
403: + "a=rtpmap:0 PCMU/8000\r\n"
404: + "a=rtpmap:4 G723/8000\r\n"
405: + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n";
406:
407: request.setContent(sdpData, contentTypeHeader);
408:
409: // The following is the preferred method to route requests
410: // to the peer. Create a route header and set the "lr"
411: // parameter for the router header.
412:
413: Address address = protocolObjects.addressFactory
414: .createAddress("<sip:" + PEER_ADDRESS + ":"
415: + PEER_PORT + ">");
416: // SipUri sipUri = (SipUri) address.getURI();
417: // sipUri.setPort(PEER_PORT);
418:
419: RouteHeader routeHeader = protocolObjects.headerFactory
420: .createRouteHeader(address);
421: ((SipURI) address.getURI()).setLrParam();
422: request.addHeader(routeHeader);
423: extensionHeader = protocolObjects.headerFactory
424: .createHeader("My-Other-Header",
425: "my new header value ");
426: request.addHeader(extensionHeader);
427:
428: Header callInfoHeader = protocolObjects.headerFactory
429: .createHeader("Call-Info",
430: "<http://www.antd.nist.gov>");
431: request.addHeader(callInfoHeader);
432:
433: // Create the client transaction.
434: this .inviteTid = provider.getNewClientTransaction(request);
435: this .dialog = this .inviteTid.getDialog();
436: // Note that the response may have arrived right away so
437: // we cannot check after the message is sent.
438: ReInviteTest.assertTrue(this .dialog.getState() == null);
439:
440: // send the request out.
441: this .inviteTid.sendRequest();
442:
443: } catch (Exception ex) {
444: logger.error("Unexpected exception", ex);
445: ReInviteTest.fail("unexpected exception");
446: }
447: }
448:
449: public void checkState() {
450: ReInviteTest.assertTrue("Expect to send a re-invite",
451: reInviteCount == 1 && this .okReceived);
452: ReInviteTest.assertTrue(
453: "Expect to send a bye and get OK for the bye",
454: this .byeSent && this .byeOkRecieved);
455: ReInviteTest.assertEquals("Expecting a re-invite",
456: this .reInviteReceivedCount, 1);
457:
458: }
459:
460: /*
461: * (non-Javadoc)
462: *
463: * @see javax.sip.SipListener#processIOException(javax.sip.IOExceptionEvent)
464: */
465: public void processIOException(IOExceptionEvent exceptionEvent) {
466: logger.error("IO Exception!");
467: ReInviteTest.fail("Unexpected exception");
468:
469: }
470:
471: /*
472: * (non-Javadoc)
473: *
474: * @see javax.sip.SipListener#processTransactionTerminated(javax.sip.TransactionTerminatedEvent)
475: */
476: public void processTransactionTerminated(
477: TransactionTerminatedEvent transactionTerminatedEvent) {
478:
479: logger.info("Transaction Terminated Event!");
480: }
481:
482: /*
483: * (non-Javadoc)
484: *
485: * @see javax.sip.SipListener#processDialogTerminated(javax.sip.DialogTerminatedEvent)
486: */
487: public void processDialogTerminated(
488: DialogTerminatedEvent dialogTerminatedEvent) {
489: logger.info("Dialog Terminated Event!");
490:
491: }
492: }
|