PageRenderTime 60ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/servers/jain-sip-ha/jboss-4/src/test/java/org/mobicents/ha/javax/sip/SimpleDialogRecoveryTest.java

http://mobicents.googlecode.com/
Java | 1116 lines | 754 code | 200 blank | 162 comment | 60 complexity | df8515dfeb5fc506b3ed8cee67159f77 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.mobicents.ha.javax.sip;
  23. import gov.nist.javax.sip.stack.SIPDialog;
  24. import java.io.ByteArrayInputStream;
  25. import java.io.ByteArrayOutputStream;
  26. import java.io.IOException;
  27. import java.io.ObjectInputStream;
  28. import java.io.ObjectOutputStream;
  29. import java.text.ParseException;
  30. import java.util.ArrayList;
  31. import java.util.Collection;
  32. import java.util.Iterator;
  33. import java.util.Properties;
  34. import java.util.Timer;
  35. import java.util.TimerTask;
  36. import javax.sip.ClientTransaction;
  37. import javax.sip.Dialog;
  38. import javax.sip.DialogState;
  39. import javax.sip.DialogTerminatedEvent;
  40. import javax.sip.IOExceptionEvent;
  41. import javax.sip.InvalidArgumentException;
  42. import javax.sip.ListeningPoint;
  43. import javax.sip.PeerUnavailableException;
  44. import javax.sip.RequestEvent;
  45. import javax.sip.ResponseEvent;
  46. import javax.sip.ServerTransaction;
  47. import javax.sip.SipException;
  48. import javax.sip.SipFactory;
  49. import javax.sip.SipListener;
  50. import javax.sip.SipProvider;
  51. import javax.sip.SipStack;
  52. import javax.sip.TimeoutEvent;
  53. import javax.sip.Transaction;
  54. import javax.sip.TransactionState;
  55. import javax.sip.TransactionTerminatedEvent;
  56. import javax.sip.address.Address;
  57. import javax.sip.address.AddressFactory;
  58. import javax.sip.address.SipURI;
  59. import javax.sip.header.CSeqHeader;
  60. import javax.sip.header.CallIdHeader;
  61. import javax.sip.header.ContactHeader;
  62. import javax.sip.header.ContentTypeHeader;
  63. import javax.sip.header.FromHeader;
  64. import javax.sip.header.Header;
  65. import javax.sip.header.HeaderFactory;
  66. import javax.sip.header.MaxForwardsHeader;
  67. import javax.sip.header.RecordRouteHeader;
  68. import javax.sip.header.RouteHeader;
  69. import javax.sip.header.ToHeader;
  70. import javax.sip.header.ViaHeader;
  71. import javax.sip.message.MessageFactory;
  72. import javax.sip.message.Request;
  73. import javax.sip.message.Response;
  74. import junit.framework.TestCase;
  75. /**
  76. * This test aims to test Mobicents Jain Sip failover recovery.
  77. * Shootist on port 5060 shoots at a stateless proxy on prt 5050 (scaled down version of a balancer)
  78. * Stateless proxy redirect to Shootme on port 5070
  79. * on ACK, the Shootme stop itself and start the other shootme node on port 5080 and pass to him its current dialogs
  80. * on BYE or other in-dialog requests, the stateless proxy forwards to recovery shootme on port 5080
  81. * Shootme recovery sends OK to BYE.
  82. *
  83. * @author <A HREF="mailto:jean.deruelle@gmail.com">Jean Deruelle</A>
  84. *
  85. */
  86. public class SimpleDialogRecoveryTest extends TestCase {
  87. public static final String IP_ADDRESS = "192.168.0.11";
  88. public static final int BALANCER_PORT = 5050;
  89. private static AddressFactory addressFactory;
  90. private static MessageFactory messageFactory;
  91. private static HeaderFactory headerFactory;
  92. Shootist shootist;
  93. Shootme shootme;
  94. Shootme shootmeRecoveryNode;
  95. Balancer balancer;
  96. class Balancer implements SipListener {
  97. private String myHost;
  98. private int myPort;
  99. private SipStack sipStack;
  100. private SipProvider sipProvider;
  101. public Balancer(String host, int port) {
  102. this.myHost = host;
  103. this.myPort = port;
  104. }
  105. public void start() throws IllegalStateException {
  106. SipFactory sipFactory = null;
  107. sipStack = null;
  108. Properties properties = new Properties();
  109. properties.setProperty("javax.sip.RETRANSMISSION_FILTER", "true");
  110. properties.setProperty("javax.sip.STACK_NAME", "StatelessForwarder");
  111. properties.setProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "off");
  112. // You need 16 for logging traces. 32 for debug + traces.
  113. // Your code will limp at 32 but it is best for debugging.
  114. properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
  115. properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
  116. "logs/statelessforwarderdebug.txt");
  117. properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "logs/statelessforwarderlog.xml");
  118. try {
  119. // Create SipStack object
  120. sipFactory = SipFactory.getInstance();
  121. sipFactory.setPathName("gov.nist");
  122. sipStack = sipFactory.createSipStack(properties);
  123. headerFactory = sipFactory.createHeaderFactory();
  124. addressFactory = sipFactory.createAddressFactory();
  125. messageFactory = sipFactory.createMessageFactory();
  126. ListeningPoint lp = sipStack.createListeningPoint(myHost, myPort, ListeningPoint.UDP);
  127. sipProvider = sipStack.createSipProvider(lp);
  128. sipProvider.addSipListener(this);
  129. sipStack.start();
  130. } catch (Exception ex) {
  131. throw new IllegalStateException("Cant create sip objects and lps due to["+ex.getMessage()+"]", ex);
  132. }
  133. }
  134. public void processDialogTerminated(
  135. DialogTerminatedEvent dialogTerminatedEvent) {
  136. // TODO Auto-generated method stub
  137. }
  138. public void processIOException(IOExceptionEvent exceptionEvent) {
  139. // TODO Auto-generated method stub
  140. }
  141. public void processRequest(RequestEvent requestEvent) {
  142. try {
  143. Request request = requestEvent.getRequest();
  144. ViaHeader viaHeader = headerFactory.createViaHeader(
  145. this.myHost, this.myPort, ListeningPoint.UDP, "z9hG4bK"+Math.random()*31+""+System.currentTimeMillis());
  146. //Decreasing the Max Forward Header
  147. MaxForwardsHeader maxForwardsHeader = (MaxForwardsHeader) request.getHeader(MaxForwardsHeader.NAME);
  148. if (maxForwardsHeader == null) {
  149. maxForwardsHeader = headerFactory.createMaxForwardsHeader(70);
  150. request.addHeader(maxForwardsHeader);
  151. } else {
  152. maxForwardsHeader.setMaxForwards(maxForwardsHeader.getMaxForwards() - 1);
  153. }
  154. // Add the via header to the top of the header list.
  155. request.addHeader(viaHeader);
  156. //Removing first routeHeader if it is for us
  157. RouteHeader routeHeader = (RouteHeader) request.getHeader(RouteHeader.NAME);
  158. if(routeHeader != null) {
  159. SipURI routeUri = (SipURI)routeHeader.getAddress().getURI();
  160. if(routeUri.getHost().equalsIgnoreCase(myHost) && routeUri.getPort() == myPort) {
  161. request.removeFirst(RouteHeader.NAME);
  162. }
  163. }
  164. // Record route the invite so the bye comes to me.
  165. if (request.getMethod().equals(Request.INVITE) || request.getMethod().equals(Request.SUBSCRIBE)) {
  166. SipURI sipUri = addressFactory
  167. .createSipURI(null, sipProvider.getListeningPoint(
  168. ListeningPoint.UDP).getIPAddress());
  169. sipUri.setPort(sipProvider.getListeningPoint(ListeningPoint.UDP).getPort());
  170. //See RFC 3261 19.1.1 for lr parameter
  171. sipUri.setLrParam();
  172. Address address = addressFactory.createAddress(sipUri);
  173. address.setURI(sipUri);
  174. RecordRouteHeader recordRoute = headerFactory
  175. .createRecordRouteHeader(address);
  176. request.addHeader(recordRoute);
  177. //Adding Route Header
  178. SipURI routeSipUri = addressFactory
  179. .createSipURI(null, IP_ADDRESS);
  180. routeSipUri.setPort(5070);
  181. routeSipUri.setLrParam();
  182. RouteHeader route = headerFactory.createRouteHeader(addressFactory.createAddress(routeSipUri));
  183. request.addFirst(route);
  184. }
  185. else if (!Request.ACK.equals(request.getMethod())) {
  186. //Adding Route Header
  187. if(((SipURI)request.getRequestURI()).getPort() == 5070) {
  188. SipURI routeSipUri = addressFactory
  189. .createSipURI(null, IP_ADDRESS);
  190. routeSipUri.setPort(5080);
  191. routeSipUri.setLrParam();
  192. RouteHeader route = headerFactory.createRouteHeader(addressFactory.createAddress(routeSipUri));
  193. request.addFirst(route);
  194. }
  195. }
  196. //sending request
  197. sipProvider.sendRequest(request);
  198. } catch (Exception ex) {
  199. ex.printStackTrace();
  200. }
  201. }
  202. public void processResponse(ResponseEvent responseEvent) {
  203. try {
  204. Response response = responseEvent.getResponse();
  205. SipProvider sender=null;
  206. // Topmost via header is me. As it is reposne to external reqeust
  207. response.removeFirst(ViaHeader.NAME);
  208. sender=this.sipProvider;
  209. sender.sendResponse(response);
  210. } catch (Exception ex) {
  211. ex.printStackTrace();
  212. }
  213. }
  214. public void processTimeout(TimeoutEvent timeoutEvent) {
  215. // TODO Auto-generated method stub
  216. }
  217. public void processTransactionTerminated(
  218. TransactionTerminatedEvent transactionTerminatedEvent) {
  219. // TODO Auto-generated method stub
  220. }
  221. }
  222. class Shootme implements SipListener {
  223. private SipStack sipStack;
  224. private static final String myAddress = IP_ADDRESS;
  225. private String stackName;
  226. public int myPort = 5070;
  227. protected ServerTransaction inviteTid;
  228. private Response okResponse;
  229. private Request inviteRequest;
  230. private Dialog dialog;
  231. public boolean callerSendsBye = true;
  232. private SipProvider sipProvider;
  233. private boolean byeTaskRunning;
  234. public Shootme(String stackName, int myPort, boolean callerSendsBye) {
  235. this.stackName = stackName;
  236. this.myPort = myPort;
  237. this.callerSendsBye = callerSendsBye;
  238. System.setProperty("jgroups.bind_addr", IP_ADDRESS);
  239. System.setProperty("java.net.preferIPv4Stack", "true");
  240. }
  241. class ByeTask extends TimerTask {
  242. Dialog dialog;
  243. public ByeTask(Dialog dialog) {
  244. this.dialog = dialog;
  245. }
  246. public void run () {
  247. try {
  248. Request byeRequest = this.dialog.createRequest(Request.BYE);
  249. ClientTransaction ct = sipProvider.getNewClientTransaction(byeRequest);
  250. dialog.sendRequest(ct);
  251. } catch (Exception ex) {
  252. ex.printStackTrace();
  253. fail("Unexpected exception ");
  254. }
  255. }
  256. }
  257. class MyTimerTask extends TimerTask {
  258. Shootme shootme;
  259. public MyTimerTask(Shootme shootme) {
  260. this.shootme = shootme;
  261. }
  262. public void run() {
  263. shootme.sendInviteOK();
  264. }
  265. }
  266. protected static final String usageString = "java "
  267. + "examples.shootist.Shootist \n"
  268. + ">>>> is your class path set to the root?";
  269. public void processRequest(RequestEvent requestEvent) {
  270. Request request = requestEvent.getRequest();
  271. ServerTransaction serverTransactionId = requestEvent
  272. .getServerTransaction();
  273. System.out.println("\n\nRequest " + request.getMethod()
  274. + " received at " + sipStack.getStackName()
  275. + " with server transaction id " + serverTransactionId);
  276. if (request.getMethod().equals(Request.INVITE)) {
  277. processInvite(requestEvent, serverTransactionId);
  278. } else if (request.getMethod().equals(Request.ACK)) {
  279. processAck(requestEvent, serverTransactionId);
  280. } else if (request.getMethod().equals(Request.BYE)) {
  281. processBye(requestEvent, serverTransactionId);
  282. } else if (request.getMethod().equals(Request.CANCEL)) {
  283. processCancel(requestEvent, serverTransactionId);
  284. } else {
  285. try {
  286. serverTransactionId.sendResponse( messageFactory.createResponse( 202, request ) );
  287. // send one back
  288. SipProvider prov = (SipProvider) requestEvent.getSource();
  289. Request refer = requestEvent.getDialog().createRequest("REFER");
  290. requestEvent.getDialog().sendRequest( prov.getNewClientTransaction(refer) );
  291. } catch (SipException e) {
  292. // TODO Auto-generated catch block
  293. e.printStackTrace();
  294. } catch (InvalidArgumentException e) {
  295. // TODO Auto-generated catch block
  296. e.printStackTrace();
  297. } catch (ParseException e) {
  298. // TODO Auto-generated catch block
  299. e.printStackTrace();
  300. }
  301. }
  302. }
  303. public void processResponse(ResponseEvent responseEvent) {
  304. }
  305. /**
  306. * Process the ACK request. Send the bye and complete the call flow.
  307. */
  308. public void processAck(RequestEvent requestEvent,
  309. ServerTransaction serverTransaction) {
  310. try {
  311. System.out.println("shootme: got an ACK! ");
  312. System.out.println("Dialog State = " + dialog.getState());
  313. // SipProvider provider = (SipProvider) requestEvent.getSource();
  314. //stopping the node
  315. // Collection<Dialog> dialogs=((SipStackImpl)sipStack).getDialogs(DialogState.CONFIRMED);
  316. stop();
  317. // shootmeRecoveryNode.init();
  318. //if (!callerSendsBye && !byeTaskRunning) {
  319. //byeTaskRunning = true;
  320. //new Timer().schedule(new ByeTask(dialog), 4000) ;
  321. //}
  322. } catch (Exception ex) {
  323. ex.printStackTrace();
  324. }
  325. }
  326. /**
  327. * Process the invite request.
  328. */
  329. public void processInvite(RequestEvent requestEvent,
  330. ServerTransaction serverTransaction) {
  331. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  332. Request request = requestEvent.getRequest();
  333. try {
  334. System.out.println("shootme: got an Invite sending Trying");
  335. // System.out.println("shootme: " + request);
  336. Response response = messageFactory.createResponse(Response.RINGING,
  337. request);
  338. ServerTransaction st = requestEvent.getServerTransaction();
  339. if (st == null) {
  340. st = sipProvider.getNewServerTransaction(request);
  341. }
  342. dialog = st.getDialog();
  343. st.sendResponse(response);
  344. this.okResponse = messageFactory.createResponse(Response.OK,
  345. request);
  346. Address address = addressFactory.createAddress("Shootme <sip:"
  347. + myAddress + ":" + myPort + ">");
  348. ContactHeader contactHeader = headerFactory
  349. .createContactHeader(address);
  350. response.addHeader(contactHeader);
  351. ToHeader toHeader = (ToHeader) okResponse.getHeader(ToHeader.NAME);
  352. toHeader.setTag("4321"); // Application is supposed to set.
  353. okResponse.addHeader(contactHeader);
  354. this.inviteTid = st;
  355. // Defer sending the OK to simulate the phone ringing.
  356. // Answered in 1 second ( this guy is fast at taking calls)
  357. this.inviteRequest = request;
  358. new Timer().schedule(new MyTimerTask(this), 1000);
  359. } catch (Exception ex) {
  360. ex.printStackTrace();
  361. System.exit(0);
  362. }
  363. }
  364. private void sendInviteOK() {
  365. try {
  366. if (inviteTid.getState() != TransactionState.COMPLETED) {
  367. System.out.println("shootme: Dialog state before 200: "
  368. + inviteTid.getDialog().getState());
  369. inviteTid.sendResponse(okResponse);
  370. System.out.println("shootme: Dialog state after 200: "
  371. + inviteTid.getDialog().getState());
  372. }
  373. } catch (SipException ex) {
  374. ex.printStackTrace();
  375. } catch (InvalidArgumentException ex) {
  376. ex.printStackTrace();
  377. }
  378. }
  379. /**
  380. * Process the bye request.
  381. */
  382. public void processBye(RequestEvent requestEvent,
  383. ServerTransaction serverTransactionId) {
  384. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  385. Request request = requestEvent.getRequest();
  386. Dialog dialog = requestEvent.getDialog();
  387. System.out.println("local party = " + dialog.getLocalParty());
  388. try {
  389. System.out.println("shootme: got a bye sending OK.");
  390. Response response = messageFactory.createResponse(200, request);
  391. serverTransactionId.sendResponse(response);
  392. System.out.println("Dialog State is "
  393. + serverTransactionId.getDialog().getState());
  394. } catch (Exception ex) {
  395. ex.printStackTrace();
  396. System.exit(0);
  397. }
  398. }
  399. public void processCancel(RequestEvent requestEvent,
  400. ServerTransaction serverTransactionId) {
  401. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  402. Request request = requestEvent.getRequest();
  403. try {
  404. System.out.println("shootme: got a cancel.");
  405. if (serverTransactionId == null) {
  406. System.out.println("shootme: null tid.");
  407. return;
  408. }
  409. Response response = messageFactory.createResponse(200, request);
  410. serverTransactionId.sendResponse(response);
  411. if (dialog.getState() != DialogState.CONFIRMED) {
  412. response = messageFactory.createResponse(
  413. Response.REQUEST_TERMINATED, inviteRequest);
  414. inviteTid.sendResponse(response);
  415. }
  416. } catch (Exception ex) {
  417. ex.printStackTrace();
  418. System.exit(0);
  419. }
  420. }
  421. public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
  422. Transaction transaction;
  423. if (timeoutEvent.isServerTransaction()) {
  424. transaction = timeoutEvent.getServerTransaction();
  425. } else {
  426. transaction = timeoutEvent.getClientTransaction();
  427. }
  428. System.out.println("state = " + transaction.getState());
  429. System.out.println("dialog = " + transaction.getDialog());
  430. System.out.println("dialogState = "
  431. + transaction.getDialog().getState());
  432. System.out.println("Transaction Time out");
  433. }
  434. public void init() {
  435. SipFactory sipFactory = null;
  436. sipStack = null;
  437. sipFactory = SipFactory.getInstance();
  438. sipFactory.setPathName("org.mobicents.ha");
  439. Properties properties = new Properties();
  440. properties.setProperty("org.mobicents.ha.javax.sip.CACHE_CLASS_NAME", "org.mobicents.ha.javax.sip.cache.JBossTreeSipCache");
  441. properties.setProperty("javax.sip.STACK_NAME", stackName);
  442. //properties.setProperty("javax.sip.OUTBOUND_PROXY", Integer
  443. // .toString(BALANCER_PORT));
  444. // You need 16 for logging traces. 32 for debug + traces.
  445. // Your code will limp at 32 but it is best for debugging.
  446. properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
  447. properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "logs/" +
  448. stackName + "debug.txt");
  449. properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "logs/" +
  450. stackName + "log.xml");
  451. try {
  452. // Create SipStack object
  453. sipStack = sipFactory.createSipStack(properties);
  454. System.out.println("sipStack = " + sipStack);
  455. } catch (PeerUnavailableException e) {
  456. // could not find
  457. // gov.nist.jain.protocol.ip.sip.SipStackImpl
  458. // in the classpath
  459. e.printStackTrace();
  460. System.err.println(e.getMessage());
  461. if (e.getCause() != null)
  462. e.getCause().printStackTrace();
  463. System.exit(0);
  464. }
  465. try {
  466. headerFactory = sipFactory.createHeaderFactory();
  467. addressFactory = sipFactory.createAddressFactory();
  468. messageFactory = sipFactory.createMessageFactory();
  469. ListeningPoint lp = sipStack.createListeningPoint(myAddress,
  470. myPort, ListeningPoint.UDP);
  471. Shootme listener = this;
  472. sipProvider = sipStack.createSipProvider(lp);
  473. System.out.println("udp provider " + sipProvider);
  474. sipProvider.addSipListener(listener);
  475. // if(dialogs != null) {
  476. // Collection<Dialog> serializedDialogs = simulateDialogSerialization(dialogs);
  477. // for (Dialog dialog : serializedDialogs) {
  478. // ((SIPDialog)dialog).setSipProvider((SipProviderImpl)sipProvider);
  479. // ((SipStackImpl)sipStack).putDialog((SIPDialog)dialog);
  480. // }
  481. // this.dialog = (SIPDialog)serializedDialogs.iterator().next();
  482. // }
  483. sipStack.start();
  484. if(!callerSendsBye && this.dialog != null) {
  485. try {
  486. Request byeRequest = this.dialog.createRequest(Request.BYE);
  487. ClientTransaction ct = sipProvider.getNewClientTransaction(byeRequest);
  488. System.out.println("sending BYE " + byeRequest);
  489. dialog.sendRequest(ct);
  490. } catch (Exception ex) {
  491. ex.printStackTrace();
  492. fail("Unexpected exception ");
  493. }
  494. }
  495. } catch (Exception ex) {
  496. System.out.println(ex.getMessage());
  497. ex.printStackTrace();
  498. fail("Unexpected exception");
  499. }
  500. }
  501. private Collection<Dialog> simulateDialogSerialization(
  502. Collection<Dialog> dialogs) {
  503. Collection<Dialog> serializedDialogs = new ArrayList<Dialog>();
  504. for (Dialog dialog : dialogs) {
  505. try{
  506. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  507. ObjectOutputStream out = new ObjectOutputStream(baos);
  508. out.writeObject(dialog);
  509. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  510. ObjectInputStream in =new ObjectInputStream(bais);
  511. SIPDialog serializedDialog = (SIPDialog)in.readObject();
  512. serializedDialogs.add(serializedDialog);
  513. out.close();
  514. in.close();
  515. baos.close();
  516. bais.close();
  517. } catch (IOException e) {
  518. e.printStackTrace();
  519. } catch (ClassNotFoundException e) {
  520. e.printStackTrace();
  521. }
  522. }
  523. return serializedDialogs;
  524. }
  525. public void processIOException(IOExceptionEvent exceptionEvent) {
  526. System.out.println("IOException");
  527. }
  528. public void processTransactionTerminated(
  529. TransactionTerminatedEvent transactionTerminatedEvent) {
  530. if (transactionTerminatedEvent.isServerTransaction())
  531. System.out.println("Transaction terminated event recieved"
  532. + transactionTerminatedEvent.getServerTransaction());
  533. else
  534. System.out.println("Transaction terminated "
  535. + transactionTerminatedEvent.getClientTransaction());
  536. }
  537. public void processDialogTerminated(
  538. DialogTerminatedEvent dialogTerminatedEvent) {
  539. System.out.println("Dialog terminated event recieved");
  540. Dialog d = dialogTerminatedEvent.getDialog();
  541. System.out.println("Local Party = " + d.getLocalParty());
  542. }
  543. public void stop() {
  544. stopSipStack(sipStack, this);
  545. }
  546. }
  547. class Shootist implements SipListener {
  548. private SipProvider sipProvider;
  549. private SipStack sipStack;
  550. private ContactHeader contactHeader;
  551. private ListeningPoint udpListeningPoint;
  552. private ClientTransaction inviteTid;
  553. private Dialog dialog;
  554. private boolean byeTaskRunning;
  555. public boolean callerSendsBye = true;
  556. class ByeTask extends TimerTask {
  557. Dialog dialog;
  558. public ByeTask(Dialog dialog) {
  559. this.dialog = dialog;
  560. }
  561. public void run () {
  562. try {
  563. Request byeRequest = this.dialog.createRequest(Request.BYE);
  564. ClientTransaction ct = sipProvider.getNewClientTransaction(byeRequest);
  565. dialog.sendRequest(ct);
  566. } catch (Exception ex) {
  567. ex.printStackTrace();
  568. fail("Unexpected exception ");
  569. }
  570. }
  571. }
  572. public Shootist(boolean callerSendsBye) {
  573. this.callerSendsBye = callerSendsBye;
  574. }
  575. public void processRequest(RequestEvent requestReceivedEvent) {
  576. Request request = requestReceivedEvent.getRequest();
  577. ServerTransaction serverTransactionId = requestReceivedEvent
  578. .getServerTransaction();
  579. System.out.println("\n\nRequest " + request.getMethod()
  580. + " received at " + sipStack.getStackName()
  581. + " with server transaction id " + serverTransactionId);
  582. // We are the UAC so the only request we get is the BYE.
  583. if (request.getMethod().equals(Request.BYE))
  584. processBye(request, serverTransactionId);
  585. else {
  586. try {
  587. serverTransactionId.sendResponse( messageFactory.createResponse(202,request) );
  588. } catch (Exception e) {
  589. e.printStackTrace();
  590. fail("Unxepcted exception ");
  591. }
  592. }
  593. }
  594. public void processBye(Request request,
  595. ServerTransaction serverTransactionId) {
  596. try {
  597. System.out.println("shootist: got a bye .");
  598. if (serverTransactionId == null) {
  599. System.out.println("shootist: null TID.");
  600. return;
  601. }
  602. Dialog dialog = serverTransactionId.getDialog();
  603. System.out.println("Dialog State = " + dialog.getState());
  604. Response response = messageFactory.createResponse(200, request);
  605. serverTransactionId.sendResponse(response);
  606. System.out.println("shootist: Sending OK.");
  607. System.out.println("Dialog State = " + dialog.getState());
  608. } catch (Exception ex) {
  609. fail("Unexpected exception");
  610. }
  611. }
  612. // Save the created ACK request, to respond to retransmitted 2xx
  613. private Request ackRequest;
  614. public boolean okToByeReceived;
  615. public void processResponse(ResponseEvent responseReceivedEvent) {
  616. System.out.println("Got a response");
  617. Response response = (Response) responseReceivedEvent.getResponse();
  618. ClientTransaction tid = responseReceivedEvent.getClientTransaction();
  619. CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
  620. System.out.println("Response received : Status Code = "
  621. + response.getStatusCode() + " " + cseq);
  622. if (tid == null) {
  623. // RFC3261: MUST respond to every 2xx
  624. if (ackRequest!=null && dialog!=null) {
  625. System.out.println("re-sending ACK");
  626. try {
  627. dialog.sendAck(ackRequest);
  628. } catch (SipException se) {
  629. se.printStackTrace();
  630. fail("Unxpected exception ");
  631. }
  632. }
  633. return;
  634. }
  635. // If the caller is supposed to send the bye
  636. if ( callerSendsBye && !byeTaskRunning) {
  637. byeTaskRunning = true;
  638. new Timer().schedule(new ByeTask(dialog), 4000) ;
  639. }
  640. System.out.println("transaction state is " + tid.getState());
  641. System.out.println("Dialog = " + tid.getDialog());
  642. System.out.println("Dialog State is " + tid.getDialog().getState());
  643. assertSame("Checking dialog identity",tid.getDialog(), this.dialog);
  644. try {
  645. if (response.getStatusCode() == Response.OK) {
  646. if (cseq.getMethod().equals(Request.INVITE)) {
  647. System.out.println("Dialog after 200 OK " + dialog);
  648. System.out.println("Dialog State after 200 OK " + dialog.getState());
  649. Request ackRequest = dialog.createAck(cseq.getSeqNumber());
  650. System.out.println("Sending ACK");
  651. dialog.sendAck(ackRequest);
  652. // JvB: test REFER, reported bug in tag handling
  653. // Request referRequest = dialog.createRequest("REFER");
  654. // //simulating a balancer that will forward the request to the recovery node
  655. // SipURI referRequestURI = addressFactory.createSipURI(null, "127.0.0.1:5080");
  656. // referRequest.setRequestURI(referRequestURI);
  657. // dialog.sendRequest( sipProvider.getNewClientTransaction(referRequest));
  658. //
  659. } else if (cseq.getMethod().equals(Request.CANCEL)) {
  660. if (dialog.getState() == DialogState.CONFIRMED) {
  661. // oops cancel went in too late. Need to hang up the
  662. // dialog.
  663. System.out
  664. .println("Sending BYE -- cancel went in too late !!");
  665. Request byeRequest = dialog.createRequest(Request.BYE);
  666. ClientTransaction ct = sipProvider
  667. .getNewClientTransaction(byeRequest);
  668. dialog.sendRequest(ct);
  669. }
  670. } else if (cseq.getMethod().equals(Request.BYE)) {
  671. okToByeReceived = true;
  672. }
  673. }
  674. } catch (Exception ex) {
  675. ex.printStackTrace();
  676. System.exit(0);
  677. }
  678. }
  679. public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
  680. System.out.println("Transaction Time out");
  681. }
  682. public void sendCancel() {
  683. try {
  684. System.out.println("Sending cancel");
  685. Request cancelRequest = inviteTid.createCancel();
  686. ClientTransaction cancelTid = sipProvider
  687. .getNewClientTransaction(cancelRequest);
  688. cancelTid.sendRequest();
  689. } catch (Exception ex) {
  690. ex.printStackTrace();
  691. }
  692. }
  693. public void init() {
  694. SipFactory sipFactory = null;
  695. sipStack = null;
  696. sipFactory = SipFactory.getInstance();
  697. sipFactory.setPathName("gov.nist");
  698. Properties properties = new Properties();
  699. // If you want to try TCP transport change the following to
  700. String transport = "udp";
  701. String peerHostPort = IP_ADDRESS + ":" + BALANCER_PORT;
  702. properties.setProperty("javax.sip.OUTBOUND_PROXY", peerHostPort + "/"
  703. + transport);
  704. // If you want to use UDP then uncomment this.
  705. properties.setProperty("javax.sip.STACK_NAME", "shootist");
  706. // The following properties are specific to nist-sip
  707. // and are not necessarily part of any other jain-sip
  708. // implementation.
  709. // You can set a max message size for tcp transport to
  710. // guard against denial of service attack.
  711. properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
  712. "logs/shootistdebug.txt");
  713. properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
  714. "logs/shootistlog.xml");
  715. // Drop the client connection after we are done with the transaction.
  716. properties.setProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS",
  717. "false");
  718. // Set to 0 (or NONE) in your production code for max speed.
  719. // You need 16 (or TRACE) for logging traces. 32 (or DEBUG) for debug + traces.
  720. // Your code will limp at 32 but it is best for debugging.
  721. properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "DEBUG");
  722. try {
  723. // Create SipStack object
  724. sipStack = sipFactory.createSipStack(properties);
  725. System.out.println("createSipStack " + sipStack);
  726. } catch (PeerUnavailableException e) {
  727. // could not find
  728. // gov.nist.jain.protocol.ip.sip.SipStackImpl
  729. // in the classpath
  730. e.printStackTrace();
  731. System.err.println(e.getMessage());
  732. System.exit(0);
  733. }
  734. try {
  735. headerFactory = sipFactory.createHeaderFactory();
  736. addressFactory = sipFactory.createAddressFactory();
  737. messageFactory = sipFactory.createMessageFactory();
  738. udpListeningPoint = sipStack.createListeningPoint(IP_ADDRESS, 5060, "udp");
  739. sipProvider = sipStack.createSipProvider(udpListeningPoint);
  740. Shootist listener = this;
  741. sipProvider.addSipListener(listener);
  742. String fromName = "BigGuy";
  743. String fromSipAddress = "here.com";
  744. String fromDisplayName = "The Master Blaster";
  745. String toSipAddress = "there.com";
  746. String toUser = "LittleGuy";
  747. String toDisplayName = "The Little Blister";
  748. // create >From Header
  749. SipURI fromAddress = addressFactory.createSipURI(fromName,
  750. fromSipAddress);
  751. Address fromNameAddress = addressFactory.createAddress(fromAddress);
  752. fromNameAddress.setDisplayName(fromDisplayName);
  753. FromHeader fromHeader = headerFactory.createFromHeader(
  754. fromNameAddress, "12345");
  755. // create To Header
  756. SipURI toAddress = addressFactory
  757. .createSipURI(toUser, toSipAddress);
  758. Address toNameAddress = addressFactory.createAddress(toAddress);
  759. toNameAddress.setDisplayName(toDisplayName);
  760. ToHeader toHeader = headerFactory.createToHeader(toNameAddress,
  761. null);
  762. // create Request URI
  763. SipURI requestURI = addressFactory.createSipURI(toUser,
  764. peerHostPort);
  765. // Create ViaHeaders
  766. ArrayList viaHeaders = new ArrayList();
  767. String ipAddress = udpListeningPoint.getIPAddress();
  768. ViaHeader viaHeader = headerFactory.createViaHeader(ipAddress,
  769. sipProvider.getListeningPoint(transport).getPort(),
  770. transport, null);
  771. // add via headers
  772. viaHeaders.add(viaHeader);
  773. // Create ContentTypeHeader
  774. ContentTypeHeader contentTypeHeader = headerFactory
  775. .createContentTypeHeader("application", "sdp");
  776. // Create a new CallId header
  777. CallIdHeader callIdHeader = sipProvider.getNewCallId();
  778. // Create a new Cseq header
  779. CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L,
  780. Request.INVITE);
  781. // Create a new MaxForwardsHeader
  782. MaxForwardsHeader maxForwards = headerFactory
  783. .createMaxForwardsHeader(70);
  784. // Create the request.
  785. Request request = messageFactory.createRequest(requestURI,
  786. Request.INVITE, callIdHeader, cSeqHeader, fromHeader,
  787. toHeader, viaHeaders, maxForwards);
  788. // Create contact headers
  789. String host = IP_ADDRESS;
  790. SipURI contactUrl = addressFactory.createSipURI(fromName, host);
  791. contactUrl.setPort(udpListeningPoint.getPort());
  792. contactUrl.setLrParam();
  793. // Create the contact name address.
  794. SipURI contactURI = addressFactory.createSipURI(fromName, host);
  795. contactURI.setPort(sipProvider.getListeningPoint(transport)
  796. .getPort());
  797. Address contactAddress = addressFactory.createAddress(contactURI);
  798. // Add the contact address.
  799. contactAddress.setDisplayName(fromName);
  800. contactHeader = headerFactory.createContactHeader(contactAddress);
  801. request.addHeader(contactHeader);
  802. // You can add extension headers of your own making
  803. // to the outgoing SIP request.
  804. // Add the extension header.
  805. Header extensionHeader = headerFactory.createHeader("My-Header",
  806. "my header value");
  807. request.addHeader(extensionHeader);
  808. String sdpData = "v=0\r\n"
  809. + "o=4855 13760799956958020 13760799956958020"
  810. + " IN IP4 129.6.55.78\r\n" + "s=mysession session\r\n"
  811. + "p=+46 8 52018010\r\n" + "c=IN IP4 129.6.55.78\r\n"
  812. + "t=0 0\r\n" + "m=audio 6022 RTP/AVP 0 4 18\r\n"
  813. + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:4 G723/8000\r\n"
  814. + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n";
  815. byte[] contents = sdpData.getBytes();
  816. request.setContent(contents, contentTypeHeader);
  817. // You can add as many extension headers as you
  818. // want.
  819. extensionHeader = headerFactory.createHeader("My-Other-Header",
  820. "my new header value ");
  821. request.addHeader(extensionHeader);
  822. Header callInfoHeader = headerFactory.createHeader("Call-Info",
  823. "<http://www.antd.nist.gov>");
  824. request.addHeader(callInfoHeader);
  825. // Create the client transaction.
  826. inviteTid = sipProvider.getNewClientTransaction(request);
  827. // send the request out.
  828. inviteTid.sendRequest();
  829. dialog = inviteTid.getDialog();
  830. } catch (Exception ex) {
  831. System.out.println(ex.getMessage());
  832. ex.printStackTrace();
  833. fail("Unxpected exception ");
  834. }
  835. }
  836. public void processIOException(IOExceptionEvent exceptionEvent) {
  837. System.out.println("IOException happened for "
  838. + exceptionEvent.getHost() + " port = "
  839. + exceptionEvent.getPort());
  840. }
  841. public void processTransactionTerminated(
  842. TransactionTerminatedEvent transactionTerminatedEvent) {
  843. System.out.println("Transaction terminated event recieved");
  844. }
  845. public void processDialogTerminated(
  846. DialogTerminatedEvent dialogTerminatedEvent) {
  847. System.out.println("dialogTerminatedEvent");
  848. }
  849. public void stop() {
  850. stopSipStack(sipStack, this);
  851. }
  852. }
  853. public static void stopSipStack(SipStack sipStack, SipListener listener) {
  854. Iterator<SipProvider> sipProviderIterator = sipStack.getSipProviders();
  855. try{
  856. while (sipProviderIterator.hasNext()) {
  857. SipProvider sipProvider = sipProviderIterator.next();
  858. ListeningPoint[] listeningPoints = sipProvider.getListeningPoints();
  859. for (ListeningPoint listeningPoint : listeningPoints) {
  860. sipProvider.removeListeningPoint(listeningPoint);
  861. sipStack.deleteListeningPoint(listeningPoint);
  862. listeningPoints = sipProvider.getListeningPoints();
  863. }
  864. sipProvider.removeSipListener(listener);
  865. sipStack.deleteSipProvider(sipProvider);
  866. sipProviderIterator = sipStack.getSipProviders();
  867. }
  868. } catch (Exception e) {
  869. throw new IllegalStateException("Cant remove the listening points or sip providers", e);
  870. }
  871. sipStack.stop();
  872. sipStack = null;
  873. }
  874. public void testDialogFailover() throws Exception {
  875. balancer = new Balancer(IP_ADDRESS, BALANCER_PORT);
  876. balancer.start();
  877. shootist = new Shootist(true);
  878. shootme = new Shootme("shootme", 5070, true);
  879. shootmeRecoveryNode = new Shootme("shootme_recovery", 5080, true);
  880. shootme.init();
  881. shootmeRecoveryNode.init();
  882. Thread.sleep(5000);
  883. shootist.init();
  884. Thread.sleep(10000);
  885. shootist.stop();
  886. shootmeRecoveryNode.stop();
  887. // shootme.stop();
  888. stopSipStack(balancer.sipStack, balancer);
  889. assertTrue(shootist.okToByeReceived);
  890. }
  891. // public void testDialogIdentityCalleeSendsBye() throws Exception {
  892. //
  893. // balancer = new Balancer(IP_ADDRESS, BALANCER_PORT);
  894. //
  895. // balancer.start();
  896. //
  897. // shootist = new Shootist(false);
  898. //
  899. // shootme = new Shootme("shootme", 5070, false);
  900. //
  901. // shootmeRecoveryNode = new Shootme("shootme_recovery", 5080, false);
  902. //
  903. // shootme.init();
  904. // shootmeRecoveryNode.init();
  905. // shootist.init();
  906. //
  907. // Thread.sleep(10000);
  908. //
  909. // shootist.stop();
  910. // shootmeRecoveryNode.stop();
  911. //// shootme.stop();
  912. // stopSipStack(balancer.sipStack, balancer);
  913. //
  914. //
  915. // }
  916. }