001: package examples.redirect;
002:
003: import javax.sip.*;
004: import javax.sip.address.*;
005: import javax.sip.header.*;
006: import javax.sip.message.*;
007:
008: import org.apache.log4j.ConsoleAppender;
009: import org.apache.log4j.Logger;
010: import org.apache.log4j.SimpleLayout;
011:
012: import java.util.*;
013:
014: import junit.framework.TestCase;
015:
016: /**
017: * This class is a UAC template. Shootist is the guy that shoots and shootme is
018: * the guy that gets shot.
019: *
020: * @author M. Ranganathan
021: */
022:
023: public class Shootist extends TestCase implements SipListener {
024:
025: private SipProvider sipProvider;
026:
027: private ProtocolObjects protocolObjects;
028:
029: private ContactHeader contactHeader;
030:
031: private ListeningPoint listeningPoint;
032:
033: private ClientTransaction inviteTid;
034:
035: private Dialog dialog;
036:
037: public static final int myPort = 5080;
038:
039: private int peerPort;
040:
041: private String peerHostPort;
042:
043: private int dialogTerminatedCount;
044:
045: private int transctionTerminatedCount;
046:
047: private int transactionCount;
048:
049: private int dialogCount;
050:
051: private boolean byeReceived;
052:
053: private boolean redirectReceived;
054:
055: private SipURI requestURI;
056:
057: private static Logger logger = Logger.getLogger(Shootist.class);
058:
059: public void processRequest(RequestEvent requestReceivedEvent) {
060: Request request = requestReceivedEvent.getRequest();
061: ServerTransaction serverTransactionId = requestReceivedEvent
062: .getServerTransaction();
063:
064: logger.info("\n\nRequest " + request.getMethod()
065: + " received at "
066: + protocolObjects.sipStack.getStackName()
067: + " with server transaction id " + serverTransactionId);
068:
069: // We are the UAC so the only request we get is the BYE.
070: if (request.getMethod().equals(Request.BYE))
071: processBye(request, serverTransactionId);
072:
073: }
074:
075: public void processBye(Request request,
076: ServerTransaction serverTransactionId) {
077: try {
078: logger.info("shootist: got a bye . ServerTxId = "
079: + serverTransactionId);
080: this .byeReceived = true;
081: if (serverTransactionId == null) {
082: logger.info("shootist: null TID.");
083: return;
084: }
085:
086: Dialog dialog = serverTransactionId.getDialog();
087: assertTrue(dialog == this .dialog);
088: logger.info("Dialog State = " + dialog.getState());
089: Response response = protocolObjects.messageFactory
090: .createResponse(200, request);
091: serverTransactionId.sendResponse(response);
092: this .transactionCount++;
093: logger.info("shootist: Sending OK.");
094: logger.info("Dialog State = " + dialog.getState());
095: assertTrue(serverTransactionId.getState() == TransactionState.COMPLETED);
096: assertTrue(dialog.getState() == DialogState.TERMINATED);
097:
098: } catch (Exception ex) {
099: ex.printStackTrace();
100: System.exit(0);
101:
102: }
103: }
104:
105: public void processResponse(ResponseEvent responseReceivedEvent) {
106: logger.info("Got a response");
107: Response response = (Response) responseReceivedEvent
108: .getResponse();
109: ClientTransaction tid = responseReceivedEvent
110: .getClientTransaction();
111: CSeqHeader cseq = (CSeqHeader) response
112: .getHeader(CSeqHeader.NAME);
113:
114: logger.info("Response received : Status Code = "
115: + response.getStatusCode() + " " + cseq);
116: if (tid == null) {
117: logger.info("Stray response -- dropping ");
118: return;
119: }
120: logger.info("transaction state is " + tid.getState());
121: logger.info("Dialog = " + tid.getDialog());
122: logger.info("Dialog State is " + tid.getDialog().getState());
123:
124: try {
125: if (response.getStatusCode() == Response.OK) {
126: logger.info("response = " + response);
127: if (cseq.getMethod().equals(Request.INVITE)) {
128: Request ackRequest = dialog.createAck(cseq
129: .getSeqNumber());
130: logger.info("Sending ACK");
131: dialog.sendAck(ackRequest);
132: }
133: } else if (response.getStatusCode() == Response.MOVED_TEMPORARILY) {
134: // Dialog dies as soon as you get an error response.
135: assertTrue(tid.getDialog().getState() == DialogState.TERMINATED);
136: assertTrue(tid.getDialog() == this .dialog);
137: this .redirectReceived = true;
138: if (cseq.getMethod().equals(Request.INVITE)) {
139: // lookup the contact header
140: ContactHeader contHdr = (ContactHeader) response
141: .getHeader(ContactHeader.NAME);
142: // we can re-use the from header
143: FromHeader from = ((FromHeader) response
144: .getHeader(FromHeader.NAME));
145: // we use the to-address, but without the tag
146: ToHeader to = (ToHeader) (response
147: .getHeader(ToHeader.NAME)).clone();
148: to.removeParameter("tag");
149: // the call-id can be re-used
150: CallIdHeader callID = ((CallIdHeader) response
151: .getHeader(CallIdHeader.NAME));
152: // we take the next cseq
153: long seqNo = (((CSeqHeader) response
154: .getHeader(CSeqHeader.NAME)).getSeqNumber());
155: logger.info("seqNo = " + seqNo);
156: CSeqHeader cseqNew = protocolObjects.headerFactory
157: .createCSeqHeader(++seqNo, "INVITE");
158: // Create ViaHeaders (either use tcp or udp)
159: ArrayList viaHeaders = new ArrayList();
160: ViaHeader viaHeader = protocolObjects.headerFactory
161: .createViaHeader("127.0.0.1", sipProvider
162: .getListeningPoint(
163: protocolObjects.transport)
164: .getPort(),
165: protocolObjects.transport, null);
166: // add via headers
167: viaHeaders.add(viaHeader);
168: // create max forwards
169: MaxForwardsHeader maxForwardsHeader = protocolObjects.headerFactory
170: .createMaxForwardsHeader(10);
171: // create invite Request
172: SipURI newUri = (SipURI) this .requestURI.clone();
173: newUri.setParameter("redirection", "true");
174:
175: Request invRequest = protocolObjects.messageFactory
176: .createRequest(newUri, "INVITE", callID,
177: cseqNew, from, to, viaHeaders,
178: maxForwardsHeader);
179: // we set the Request URI to the address given
180: SipURI contactURI = protocolObjects.addressFactory
181: .createSipURI(null, this .listeningPoint
182: .getIPAddress());
183:
184: contactURI.setPort(this .listeningPoint.getPort());
185: contactURI
186: .setTransportParam(protocolObjects.transport);
187:
188: Address address = protocolObjects.addressFactory
189: .createAddress(contactURI);
190: ContactHeader contact = protocolObjects.headerFactory
191: .createContactHeader(address);
192: invRequest.addHeader(contact);
193:
194: // the contacat header in the response contains where to redirect
195: // the request to -- which in this case happens to be back to the
196: // same location.
197: ContactHeader chdr = (ContactHeader) response
198: .getHeader(ContactHeader.NAME);
199:
200: SipURI sipUri = (SipURI) chdr.getAddress().getURI();
201: sipUri.setLrParam();
202: RouteHeader routeHeader = protocolObjects.headerFactory
203: .createRouteHeader(chdr.getAddress());
204: invRequest.addHeader(routeHeader);
205:
206: logger.info("Sending INVITE to "
207: + contHdr.getAddress().getURI().toString());
208: inviteTid = sipProvider
209: .getNewClientTransaction(invRequest);
210: this .transactionCount++;
211:
212: logger.info("New TID = " + inviteTid);
213: inviteTid.sendRequest();
214: assertTrue(inviteTid.getState() == TransactionState.CALLING);
215: logger.info("sendReqeust succeeded " + inviteTid);
216: Dialog dialog = inviteTid.getDialog();
217: assertTrue("Stack must allocate a new dialog",
218: dialog != this .dialog);
219: this .dialogCount++;
220: this .dialog = dialog;
221:
222: }
223: }
224: /**
225: * end of modified code
226: */
227: } catch (Exception ex) {
228: ex.printStackTrace();
229: fail("unexpeced exception");
230: }
231:
232: }
233:
234: public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
235:
236: logger.info("Transaction Time out");
237: fail("Unexpected event");
238: }
239:
240: public SipProvider createProvider() throws Exception {
241: logger.info("Shootist: createProvider()");
242: listeningPoint = protocolObjects.sipStack.createListeningPoint(
243: "127.0.0.1", myPort, protocolObjects.transport);
244: this .sipProvider = protocolObjects.sipStack
245: .createSipProvider(listeningPoint);
246: assertTrue(
247: "listening point should be the same as what the provider returns for this transport",
248: listeningPoint == sipProvider
249: .getListeningPoint(protocolObjects.transport));
250: return sipProvider;
251:
252: }
253:
254: public void sendInvite() {
255:
256: try {
257: /**
258: * either use udp or tcp
259: */
260:
261: String fromName = "BigGuy";
262: String fromSipAddress = "here.com";
263: String fromDisplayName = "The Master Blaster";
264:
265: String toSipAddress = "there.com";
266: String toUser = "LittleGuy";
267: String toDisplayName = "The Little Blister";
268:
269: // create >From Header
270: SipURI fromAddress = protocolObjects.addressFactory
271: .createSipURI(fromName, fromSipAddress);
272:
273: Address fromNameAddress = protocolObjects.addressFactory
274: .createAddress(fromAddress);
275: fromNameAddress.setDisplayName(fromDisplayName);
276: FromHeader fromHeader = protocolObjects.headerFactory
277: .createFromHeader(fromNameAddress, "12345");
278:
279: // create To Header
280: SipURI toAddress = protocolObjects.addressFactory
281: .createSipURI(toUser, toSipAddress);
282: Address toNameAddress = protocolObjects.addressFactory
283: .createAddress(toAddress);
284: toNameAddress.setDisplayName(toDisplayName);
285: ToHeader toHeader = protocolObjects.headerFactory
286: .createToHeader(toNameAddress, null);
287:
288: // create Request URI
289: this .requestURI = protocolObjects.addressFactory
290: .createSipURI(toUser, peerHostPort);
291:
292: // Create ViaHeaders
293:
294: ArrayList viaHeaders = new ArrayList();
295: ViaHeader viaHeader = protocolObjects.headerFactory
296: .createViaHeader("127.0.0.1", sipProvider
297: .getListeningPoint(
298: protocolObjects.transport)
299: .getPort(), protocolObjects.transport, null);
300:
301: // add via headers
302: viaHeaders.add(viaHeader);
303:
304: // Create ContentTypeHeader
305: ContentTypeHeader contentTypeHeader = protocolObjects.headerFactory
306: .createContentTypeHeader("application", "sdp");
307:
308: // Create a new CallId header
309: CallIdHeader callIdHeader = sipProvider.getNewCallId();
310:
311: // Create a new Cseq header
312: CSeqHeader cSeqHeader = protocolObjects.headerFactory
313: .createCSeqHeader(1L, Request.INVITE);
314:
315: // Create a new MaxForwardsHeader
316: MaxForwardsHeader maxForwards = protocolObjects.headerFactory
317: .createMaxForwardsHeader(70);
318:
319: // Create the request.
320: Request request = protocolObjects.messageFactory
321: .createRequest(requestURI, Request.INVITE,
322: callIdHeader, cSeqHeader, fromHeader,
323: toHeader, viaHeaders, maxForwards);
324: // Create contact headers
325: String host = "127.0.0.1";
326:
327: SipURI contactUrl = protocolObjects.addressFactory
328: .createSipURI(fromName, host);
329: /**
330: * either use tcp or udp
331: */
332: contactUrl.setPort(listeningPoint.getPort());
333: contactUrl.setTransportParam(protocolObjects.transport);
334:
335: // Create the contact name address.
336:
337: Address contactAddress = protocolObjects.addressFactory
338: .createAddress(contactUrl);
339: contactUrl.setLrParam();
340:
341: // Add the contact address.
342: contactAddress.setDisplayName(fromName);
343:
344: contactHeader = protocolObjects.headerFactory
345: .createContactHeader(contactAddress);
346: request.addHeader(contactHeader);
347:
348: SipURI uri = protocolObjects.addressFactory.createSipURI(
349: null, "127.0.0.1");
350:
351: uri.setLrParam();
352: uri.setTransportParam(protocolObjects.transport);
353: uri.setPort(this .peerPort);
354:
355: Address address = protocolObjects.addressFactory
356: .createAddress(uri);
357: RouteHeader routeHeader = protocolObjects.headerFactory
358: .createRouteHeader(address);
359: request.addHeader(routeHeader);
360: // Add the extension header.
361: Header extensionHeader = protocolObjects.headerFactory
362: .createHeader("My-Header", "my header value");
363: request.addHeader(extensionHeader);
364:
365: String sdpData = "v=0\r\n"
366: + "o=4855 13760799956958020 13760799956958020"
367: + " IN IP4 129.6.55.78\r\n"
368: + "s=mysession session\r\n"
369: + "p=+46 8 52018010\r\n"
370: + "c=IN IP4 129.6.55.78\r\n" + "t=0 0\r\n"
371: + "m=audio 6022 RTP/AVP 0 4 18\r\n"
372: + "a=rtpmap:0 PCMU/8000\r\n"
373: + "a=rtpmap:4 G723/8000\r\n"
374: + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n";
375: byte[] contents = sdpData.getBytes();
376:
377: request.setContent(contents, contentTypeHeader);
378:
379: extensionHeader = protocolObjects.headerFactory
380: .createHeader("My-Other-Header",
381: "my new header value ");
382: request.addHeader(extensionHeader);
383:
384: Header callInfoHeader = protocolObjects.headerFactory
385: .createHeader("Call-Info",
386: "<http://www.antd.nist.gov>");
387: request.addHeader(callInfoHeader);
388:
389: // Create the client transaction.
390: inviteTid = sipProvider.getNewClientTransaction(request);
391:
392: // send the request out.
393: inviteTid.sendRequest();
394:
395: this .transactionCount++;
396:
397: assertTrue(inviteTid.getState() == TransactionState.CALLING);
398:
399: logger.info("client tx = " + inviteTid);
400: dialog = inviteTid.getDialog();
401: this .dialogCount++;
402: assertTrue(dialog != null);
403: assertTrue(dialog.getState() == null);
404:
405: } catch (Exception ex) {
406: logger.error(ex.getMessage(), ex);
407: fail("unexpected exception");
408: }
409: }
410:
411: public Shootist(ProtocolObjects protocolObjects) {
412: this .protocolObjects = protocolObjects;
413: this .peerPort = Shootme.myPort;
414: this .peerHostPort = "127.0.0.1:" + peerPort;
415: }
416:
417: public static void main(String args[]) throws Exception {
418: ProtocolObjects protocolObjects = new ProtocolObjects(
419: "shootist", true, "udp", "");
420: logger.addAppender(new ConsoleAppender(new SimpleLayout()));
421: Shootist shootist = new Shootist(protocolObjects);
422: shootist.createProvider();
423: shootist.sipProvider.addSipListener(shootist);
424: shootist.sendInvite();
425:
426: }
427:
428: public void processIOException(IOExceptionEvent exceptionEvent) {
429: logger.info("IOException happened for "
430: + exceptionEvent.getHost() + " port = "
431: + exceptionEvent.getPort());
432:
433: }
434:
435: public void processTransactionTerminated(
436: TransactionTerminatedEvent transactionTerminatedEvent) {
437: logger.info("Transaction terminated event recieved for "
438: + transactionTerminatedEvent.getClientTransaction());
439: this .transctionTerminatedCount++;
440: }
441:
442: public void processDialogTerminated(
443: DialogTerminatedEvent dialogTerminatedEvent) {
444: this .dialogTerminatedCount++;
445:
446: }
447:
448: public void checkState() {
449: assertTrue(dialogTerminatedCount == dialogCount);
450: assertTrue(this.byeReceived && this.redirectReceived);
451:
452: }
453: }
|