001: package examples.reinvite;
002:
003: import gov.nist.javax.sip.address.SipUri;
004:
005: import javax.sip.*;
006: import javax.sip.address.*;
007: import javax.sip.header.*;
008: import javax.sip.message.*;
009:
010: import org.apache.log4j.ConsoleAppender;
011: import org.apache.log4j.FileAppender;
012: import org.apache.log4j.Logger;
013: import org.apache.log4j.SimpleLayout;
014:
015: import java.util.*;
016:
017: import junit.framework.TestCase;
018:
019: /**
020: * This class is a UAC template. Shootist is the guy that shoots and shootme is
021: * the guy that gets shot.
022: *
023: *
024: * @author M. Ranganathan
025: */
026:
027: public class Shootist implements SipListener {
028:
029: private boolean reInviteFlag;
030:
031: private SipProvider provider;
032:
033: private int reInviteCount;
034:
035: private ContactHeader contactHeader;
036:
037: private ListeningPoint listeningPoint;
038:
039: private int counter;
040:
041: private static String PEER_ADDRESS = Shootme.myAddress;
042:
043: private static int PEER_PORT = Shootme.myPort;
044:
045: private static String peerHostPort = PEER_ADDRESS + ":" + PEER_PORT;
046:
047: // To run on two machines change these to suit.
048: public static final String myAddress = "127.0.0.1";
049:
050: private static final int myPort = 5060;
051:
052: protected ClientTransaction inviteTid;
053:
054: private boolean okReceived;
055:
056: private Dialog dialog;
057:
058: protected static final String usageString = "java "
059: + "examples.shootist.Shootist \n"
060: + ">>>> is your class path set to the root?";
061:
062: private static Logger logger = Logger.getLogger(Shootist.class);
063:
064: static {
065: try {
066: logger.addAppender(new FileAppender(new SimpleLayout(),
067: ProtocolObjects.logFileDirectory
068: + "shootistconsolelog.txt"));
069: } catch (Exception ex) {
070: throw new RuntimeException(
071: "could not open shootistconsolelog.txt");
072: }
073: }
074:
075: private static void usage() {
076: logger.info(usageString);
077: System.exit(0);
078:
079: }
080:
081: public Shootist(int count) {
082: this .counter = count;
083: }
084:
085: private void shutDownAndRestart() {
086: try {
087:
088: logger.info("nulling reference");
089: ProtocolObjects.sipStack
090: .deleteListeningPoint(listeningPoint);
091: checkState();
092: // This will close down the stack and exit all threads
093: provider.removeSipListener(this );
094: while (true) {
095: try {
096: ProtocolObjects.sipStack
097: .deleteSipProvider(provider);
098:
099: break;
100: } catch (ObjectInUseException ex) {
101: try {
102: Thread.sleep(2000);
103: } catch (InterruptedException e) {
104: continue;
105: }
106: }
107: }
108: ProtocolObjects.sipStack.stop();
109: provider = null;
110: inviteTid = null;
111: contactHeader = null;
112: this .listeningPoint = null;
113: this .reInviteCount = 0;
114: SipProvider sipProvider = this .createSipProvider();
115: sipProvider.addSipListener(this );
116: ProtocolObjects.sipStack.start();
117: // Redo this from the start.
118:
119: ProtocolObjects.init("shootist", true);
120: this .sendInvite();
121:
122: } catch (Exception ex) {
123: logger.error(ex);
124: System.exit(0);
125: }
126: }
127:
128: public void processRequest(RequestEvent requestReceivedEvent) {
129: Request request = requestReceivedEvent.getRequest();
130: ServerTransaction serverTransactionId = requestReceivedEvent
131: .getServerTransaction();
132:
133: logger.info("\n\nRequest " + request.getMethod()
134: + " received at "
135: + ProtocolObjects.sipStack.getStackName()
136: + " with server transaction id " + serverTransactionId);
137:
138: if (request.getMethod().equals(Request.BYE))
139: processBye(request, serverTransactionId);
140: else if (request.getMethod().equals(Request.INVITE))
141: processInvite(request, serverTransactionId);
142: else if (request.getMethod().equals(Request.ACK))
143: processAck(request, serverTransactionId);
144:
145: }
146:
147: /**
148: * Handle an incoming INVITE request.
149: *
150: * @param request -- request to process
151: * @param st -- server tx associated with the request.
152: */
153: public void processInvite(Request request, ServerTransaction st) {
154: try {
155: System.out.println("Processing Re-INVITE ");
156: Response response = ProtocolObjects.messageFactory
157: .createResponse(Response.OK, request);
158: ((ToHeader) response.getHeader(ToHeader.NAME))
159: .setTag(((ToHeader) request
160: .getHeader(ToHeader.NAME)).getTag());
161: response.addHeader(this .contactHeader);
162: st.sendResponse(response);
163: TestCase.assertEquals("Re-Inivte Dialog must match ",
164: this .dialog, st.getDialog());
165: } catch (Exception ex) {
166: ex.printStackTrace();
167: System.exit(0);
168: }
169: }
170:
171: /**
172: * Handle an incoming ACK.
173: *
174: * @param request
175: * @param tid
176: */
177:
178: public void processAck(Request request, ServerTransaction tid) {
179: try {
180: logger.info("Got an ACK! sending bye : " + tid);
181: if (tid != null) {
182: Dialog dialog = tid.getDialog();
183:
184: TestCase.assertSame("Dialog mismatch", dialog,
185: this .dialog);
186:
187: Request bye = dialog.createRequest(Request.BYE);
188: logger.info("bye request = " + bye);
189: MaxForwardsHeader mf = ProtocolObjects.headerFactory
190: .createMaxForwardsHeader(10);
191: bye.addHeader(mf);
192: ClientTransaction ct = provider
193: .getNewClientTransaction(bye);
194: dialog.sendRequest(ct);
195: }
196: } catch (Exception ex) {
197: ex.printStackTrace();
198: System.exit(0);
199: }
200: }
201:
202: public void processBye(Request request,
203: ServerTransaction serverTransactionId) {
204: try {
205: logger.info("shootist: got a bye .");
206: if (serverTransactionId == null) {
207: logger.info("shootist: null TID.");
208: return;
209: }
210: Dialog dialog = serverTransactionId.getDialog();
211: logger.info("Dialog State = " + dialog.getState());
212: Response response = ProtocolObjects.messageFactory
213: .createResponse(200, request);
214: serverTransactionId.sendResponse(response);
215: logger.info("shootist: Sending OK.");
216: logger.info("Dialog State = " + dialog.getState());
217:
218: if (counter-- > 0)
219: this .shutDownAndRestart();
220:
221: } catch (Exception ex) {
222: ex.printStackTrace();
223: System.exit(0);
224:
225: }
226: }
227:
228: /*
229: * (non-Javadoc)
230: * @see javax.sip.SipListener#processResponse(javax.sip.ResponseEvent)
231: */
232: public void processResponse(ResponseEvent responseReceivedEvent) {
233: logger.info("Got a response");
234:
235: Response response = (Response) responseReceivedEvent
236: .getResponse();
237: Transaction tid = responseReceivedEvent.getClientTransaction();
238:
239: logger.info("Response received with client transaction id "
240: + tid + ":\n" + response.getStatusCode());
241: if (tid == null) {
242: logger.info("Stray response -- dropping ");
243: return;
244: }
245: logger.info("transaction state is " + tid.getState());
246: logger.info("Dialog = " + tid.getDialog());
247: logger.info("Dialog State is " + tid.getDialog().getState());
248:
249: try {
250: if (response.getStatusCode() == Response.OK
251: && ((CSeqHeader) response
252: .getHeader(CSeqHeader.NAME)).getMethod()
253: .equals(Request.INVITE)) {
254:
255: // Request cancel = inviteTid.createCancel();
256: // ClientTransaction ct =
257: // sipProvider.getNewClientTransaction(cancel);
258:
259: Dialog dialog = tid.getDialog();
260: logger.info("dialogs = " + dialog + " thisdialog = "
261: + this .dialog);
262: TestCase.assertTrue("dialog mismatch",
263: dialog == this .dialog);
264:
265: Request ackRequest = dialog.createRequest(Request.ACK);
266: logger.info("Ack request to send = " + ackRequest);
267: logger.info("Sending ACK");
268: dialog.sendAck(ackRequest);
269:
270: // Send a Re INVITE
271: if (reInviteCount == 0) {
272: logger.info("Sending RE-INVITE");
273: this .sendReInvite();
274: reInviteCount++;
275: } else {
276: this .okReceived = true;
277: }
278:
279: } else if (response.getStatusCode() == Response.OK
280: && ((CSeqHeader) response
281: .getHeader(CSeqHeader.NAME)).getMethod()
282: .equals(Request.BYE)) {
283: if (this .counter-- > 0)
284: this .shutDownAndRestart();
285: }
286: } catch (Exception ex) {
287: logger.error(ex);
288: System.exit(0);
289: }
290:
291: }
292:
293: public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
294:
295: logger.info("Transaction Time out");
296: logger.info("TimeoutEvent " + timeoutEvent.getTimeout());
297: }
298:
299: public SipProvider createSipProvider() {
300: try {
301: listeningPoint = ProtocolObjects.sipStack
302: .createListeningPoint(myAddress, myPort,
303: ProtocolObjects.transport);
304:
305: provider = ProtocolObjects.sipStack
306: .createSipProvider(listeningPoint);
307: return provider;
308: } catch (Exception ex) {
309: logger.error(ex);
310: System.exit(0);
311: return null;
312: }
313: }
314:
315: /**
316: * Create and send a re-invitation.
317: *
318: * @throws Exception
319: */
320: public void sendReInvite() throws Exception {
321: Request inviteRequest = dialog.createRequest(Request.INVITE);
322: MaxForwardsHeader mf = ProtocolObjects.headerFactory
323: .createMaxForwardsHeader(10);
324: inviteRequest.setHeader(mf);
325: inviteRequest.setHeader(this .contactHeader);
326: ClientTransaction ct = provider
327: .getNewClientTransaction(inviteRequest);
328: dialog.sendRequest(ct);
329: }
330:
331: /**
332: * Create and send out the initial invite.
333: *
334: */
335: public void sendInvite() {
336:
337: try {
338:
339: // Note that a provider has multiple listening points.
340: // all the listening points must have the same IP address
341: // and port but differ in their transport parameters.
342:
343: String fromName = "BigGuy";
344: String fromSipAddress = "here.com";
345: String fromDisplayName = "The Master Blaster";
346:
347: String toSipAddress = "there.com";
348: String toUser = "LittleGuy";
349: String toDisplayName = "The Little Blister";
350:
351: // create >From Header
352: SipURI fromAddress = ProtocolObjects.addressFactory
353: .createSipURI(fromName, fromSipAddress);
354:
355: Address fromNameAddress = ProtocolObjects.addressFactory
356: .createAddress(fromAddress);
357: fromNameAddress.setDisplayName(fromDisplayName);
358: FromHeader fromHeader = ProtocolObjects.headerFactory
359: .createFromHeader(fromNameAddress, new Integer(
360: (int) (Math.random() * Integer.MAX_VALUE))
361: .toString());
362:
363: // create To Header
364: SipURI toAddress = ProtocolObjects.addressFactory
365: .createSipURI(toUser, toSipAddress);
366: Address toNameAddress = ProtocolObjects.addressFactory
367: .createAddress(toAddress);
368: toNameAddress.setDisplayName(toDisplayName);
369: ToHeader toHeader = ProtocolObjects.headerFactory
370: .createToHeader(toNameAddress, null);
371:
372: // create Request URI
373: SipURI requestURI = ProtocolObjects.addressFactory
374: .createSipURI(toUser, peerHostPort);
375:
376: // Create ViaHeaders
377:
378: ArrayList viaHeaders = new ArrayList();
379: int port = provider.getListeningPoint(
380: ProtocolObjects.transport).getPort();
381:
382: ViaHeader viaHeader = ProtocolObjects.headerFactory
383: .createViaHeader(myAddress, port,
384: ProtocolObjects.transport, null);
385:
386: // add via headers
387: viaHeaders.add(viaHeader);
388:
389: // Create ContentTypeHeader
390: ContentTypeHeader contentTypeHeader = ProtocolObjects.headerFactory
391: .createContentTypeHeader("application", "sdp");
392:
393: // Create a new CallId header
394: CallIdHeader callIdHeader = provider.getNewCallId();
395:
396: // Create a new Cseq header
397: CSeqHeader cSeqHeader = ProtocolObjects.headerFactory
398: .createCSeqHeader(1L, Request.INVITE);
399:
400: // Create a new MaxForwardsHeader
401: MaxForwardsHeader maxForwards = ProtocolObjects.headerFactory
402: .createMaxForwardsHeader(70);
403:
404: // Create the request.
405: Request request = ProtocolObjects.messageFactory
406: .createRequest(requestURI, Request.INVITE,
407: callIdHeader, cSeqHeader, fromHeader,
408: toHeader, viaHeaders, maxForwards);
409: // Create contact headers
410:
411: // Create the contact name address.
412: SipURI contactURI = ProtocolObjects.addressFactory
413: .createSipURI(fromName, myAddress);
414: contactURI.setPort(provider.getListeningPoint(
415: ProtocolObjects.transport).getPort());
416:
417: Address contactAddress = ProtocolObjects.addressFactory
418: .createAddress(contactURI);
419:
420: // Add the contact address.
421: contactAddress.setDisplayName(fromName);
422:
423: contactHeader = ProtocolObjects.headerFactory
424: .createContactHeader(contactAddress);
425: request.addHeader(contactHeader);
426:
427: // Add the extension header.
428: Header extensionHeader = ProtocolObjects.headerFactory
429: .createHeader("My-Header", "my header value");
430: request.addHeader(extensionHeader);
431:
432: String sdpData = "v=0\r\n"
433: + "o=4855 13760799956958020 13760799956958020"
434: + " IN IP4 129.6.55.78\r\n"
435: + "s=mysession session\r\n"
436: + "p=+46 8 52018010\r\n"
437: + "c=IN IP4 129.6.55.78\r\n" + "t=0 0\r\n"
438: + "m=audio 6022 RTP/AVP 0 4 18\r\n"
439: + "a=rtpmap:0 PCMU/8000\r\n"
440: + "a=rtpmap:4 G723/8000\r\n"
441: + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n";
442:
443: request.setContent(sdpData, contentTypeHeader);
444:
445: // The following is the preferred method to route requests
446: // to the peer. Create a route header and set the "lr"
447: // parameter for the router header.
448:
449: Address address = ProtocolObjects.addressFactory
450: .createAddress("<sip:" + PEER_ADDRESS + ":"
451: + PEER_PORT + ">");
452: // SipUri sipUri = (SipUri) address.getURI();
453: // sipUri.setPort(PEER_PORT);
454:
455: RouteHeader routeHeader = ProtocolObjects.headerFactory
456: .createRouteHeader(address);
457: SipUri sipUri = (SipUri) address.getURI();
458: sipUri.setLrParam();
459: request.addHeader(routeHeader);
460: extensionHeader = ProtocolObjects.headerFactory
461: .createHeader("My-Other-Header",
462: "my new header value ");
463: request.addHeader(extensionHeader);
464:
465: Header callInfoHeader = ProtocolObjects.headerFactory
466: .createHeader("Call-Info",
467: "<http://www.antd.nist.gov>");
468: request.addHeader(callInfoHeader);
469:
470: // Create the client transaction.
471: this .inviteTid = provider.getNewClientTransaction(request);
472:
473: // send the request out.
474: this .inviteTid.sendRequest();
475: this .dialog = this .inviteTid.getDialog();
476: logger.info("created dialog " + dialog);
477:
478: } catch (Exception ex) {
479: logger.error("Unexpected exception", ex);
480: usage();
481: }
482: }
483:
484: public void checkState() {
485: TestCase.assertTrue(reInviteCount == 1 && this .okReceived);
486:
487: }
488:
489: /*
490: * (non-Javadoc)
491: *
492: * @see javax.sip.SipListener#processIOException(javax.sip.IOExceptionEvent)
493: */
494: public void processIOException(IOExceptionEvent exceptionEvent) {
495: logger.info("IO Exception!");
496: TestCase.fail("Unexpected exception");
497:
498: }
499:
500: /*
501: * (non-Javadoc)
502: *
503: * @see javax.sip.SipListener#processTransactionTerminated(javax.sip.TransactionTerminatedEvent)
504: */
505: public void processTransactionTerminated(
506: TransactionTerminatedEvent transactionTerminatedEvent) {
507:
508: logger.info("Transaction Terminated Event!");
509: }
510:
511: /*
512: * (non-Javadoc)
513: *
514: * @see javax.sip.SipListener#processDialogTerminated(javax.sip.DialogTerminatedEvent)
515: */
516: public void processDialogTerminated(
517: DialogTerminatedEvent dialogTerminatedEvent) {
518: logger.info("Dialog Terminated Event!");
519:
520: }
521:
522: /////////////////////////////////////////////////////////////////////////////////
523: // main method
524: /////////////////////////////////////////////////////////////////////////////////
525: public static void main(String args[]) {
526: try {
527: ProtocolObjects.init("shootist", true);
528: logger.addAppender(new ConsoleAppender(new SimpleLayout()));
529: Shootist shootist = new Shootist(10);
530: shootist.createSipProvider();
531: shootist.provider.addSipListener(shootist);
532: shootist.sendInvite();
533: } catch (Exception ex) {
534: ex.printStackTrace();
535: }
536:
537: }
538:
539: }
|