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