PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/jain-sip-ha/jboss-5/src/test/java/org/mobicents/ha/javax/sip/B2BUADialogRecoveryTest.java

http://mobicents.googlecode.com/
Java | 1278 lines | 889 code | 200 blank | 189 comment | 107 complexity | d5f7c492dd753896f4466629fce64b4d 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

Large files files are truncated, but you can click here to view the full file

  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.Transaction;
  53. import javax.sip.TransactionState;
  54. import javax.sip.TransactionTerminatedEvent;
  55. import javax.sip.address.Address;
  56. import javax.sip.address.AddressFactory;
  57. import javax.sip.address.SipURI;
  58. import javax.sip.header.CSeqHeader;
  59. import javax.sip.header.CallIdHeader;
  60. import javax.sip.header.ContactHeader;
  61. import javax.sip.header.ContentTypeHeader;
  62. import javax.sip.header.EventHeader;
  63. import javax.sip.header.ExpiresHeader;
  64. import javax.sip.header.FromHeader;
  65. import javax.sip.header.Header;
  66. import javax.sip.header.HeaderFactory;
  67. import javax.sip.header.MaxForwardsHeader;
  68. import javax.sip.header.SubscriptionStateHeader;
  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. * Issue 1407 http://code.google.com/p/mobicents/issues/detail?id=1407
  78. *
  79. * @author <A HREF="mailto:jean.deruelle@gmail.com">Jean Deruelle</A>
  80. *
  81. */
  82. public class B2BUADialogRecoveryTest extends TestCase {
  83. public static final String IP_ADDRESS = "192.168.0.10";
  84. public static final int BALANCER_PORT = 5050;
  85. private static AddressFactory addressFactory;
  86. private static MessageFactory messageFactory;
  87. private static HeaderFactory headerFactory;
  88. Shootist shootist;
  89. Shootme shootme;
  90. SimpleB2BUA b2buaNode1;
  91. SimpleB2BUA b2buaNode2;
  92. class Shootme implements SipListener {
  93. private SipStack sipStack;
  94. private static final String myAddress = IP_ADDRESS;
  95. private String stackName;
  96. public int myPort = 5070;
  97. protected ServerTransaction inviteTid;
  98. private Response okResponse;
  99. private Request inviteRequest;
  100. private Dialog dialog;
  101. public boolean callerSendsBye = true;
  102. private SipProvider sipProvider;
  103. private boolean byeTaskRunning;
  104. private boolean secondReinviteSent;
  105. private boolean firstReinviteSent;
  106. private boolean firstTxComplete;
  107. private boolean firstReInviteComplete;
  108. private boolean secondReInviteComplete;
  109. private boolean byeReceived;
  110. private boolean subscribeTxComplete;
  111. private boolean notifyTxComplete;
  112. public Shootme(String stackName, int myPort, boolean callerSendsBye) {
  113. this.stackName = stackName;
  114. this.myPort = myPort;
  115. this.callerSendsBye = callerSendsBye;
  116. System.setProperty("jgroups.bind_addr", IP_ADDRESS);
  117. System.setProperty("java.net.preferIPv4Stack", "true");
  118. }
  119. class ByeTask extends TimerTask {
  120. Dialog dialog;
  121. public ByeTask(Dialog dialog) {
  122. this.dialog = dialog;
  123. }
  124. public void run () {
  125. try {
  126. Request byeRequest = this.dialog.createRequest(Request.BYE);
  127. ClientTransaction ct = sipProvider.getNewClientTransaction(byeRequest);
  128. dialog.sendRequest(ct);
  129. } catch (Exception ex) {
  130. ex.printStackTrace();
  131. fail("Unexpected exception ");
  132. }
  133. }
  134. }
  135. class MyTimerTask extends TimerTask {
  136. Shootme shootme;
  137. public MyTimerTask(Shootme shootme) {
  138. this.shootme = shootme;
  139. }
  140. public void run() {
  141. shootme.sendInviteOK();
  142. }
  143. }
  144. protected static final String usageString = "java "
  145. + "examples.shootist.Shootist \n"
  146. + ">>>> is your class path set to the root?";
  147. private static final long TIMEOUT = 10000;
  148. public void processRequest(RequestEvent requestEvent) {
  149. Request request = requestEvent.getRequest();
  150. ServerTransaction serverTransactionId = requestEvent
  151. .getServerTransaction();
  152. System.out.println("\n\nRequest " + request.getMethod()
  153. + " received at " + sipStack.getStackName()
  154. + " with server transaction id " + serverTransactionId);
  155. if (request.getMethod().equals(Request.INVITE)) {
  156. processInvite(requestEvent, serverTransactionId);
  157. } else if (request.getMethod().equals(Request.ACK)) {
  158. processAck(requestEvent, serverTransactionId);
  159. } else if (request.getMethod().equals(Request.BYE)) {
  160. processBye(requestEvent, serverTransactionId);
  161. } else if (request.getMethod().equals(Request.SUBSCRIBE)) {
  162. processSubscribe(requestEvent, serverTransactionId);
  163. } else if (request.getMethod().equals(Request.CANCEL)) {
  164. processCancel(requestEvent, serverTransactionId);
  165. } else {
  166. try {
  167. serverTransactionId.sendResponse( messageFactory.createResponse( 202, request ) );
  168. // send one back
  169. SipProvider prov = (SipProvider) requestEvent.getSource();
  170. Request refer = requestEvent.getDialog().createRequest("REFER");
  171. requestEvent.getDialog().sendRequest( prov.getNewClientTransaction(refer) );
  172. } catch (SipException e) {
  173. // TODO Auto-generated catch block
  174. e.printStackTrace();
  175. } catch (InvalidArgumentException e) {
  176. // TODO Auto-generated catch block
  177. e.printStackTrace();
  178. } catch (ParseException e) {
  179. // TODO Auto-generated catch block
  180. e.printStackTrace();
  181. }
  182. }
  183. }
  184. public void processResponse(ResponseEvent responseEvent) {
  185. Dialog dialog = responseEvent.getDialog();
  186. CSeqHeader cSeqHeader = (CSeqHeader)responseEvent.getResponse().getHeader(CSeqHeader.NAME);
  187. try {
  188. if(responseEvent.getResponse().getStatusCode() >= 200 && cSeqHeader.getMethod().equalsIgnoreCase(Request.INVITE)) {
  189. Request ackRequest = dialog.createAck(cSeqHeader.getSeqNumber());
  190. int port = 5080;
  191. if(firstReinviteSent) {
  192. port = 5081;
  193. firstReinviteSent = false;
  194. firstReInviteComplete = true;
  195. }
  196. if(secondReinviteSent) {
  197. secondReInviteComplete = true;
  198. }
  199. System.out.println("Sending ACK");
  200. ((SipURI)ackRequest.getRequestURI()).setPort(port);
  201. dialog.sendAck(ackRequest);
  202. if(!secondReinviteSent) {
  203. Thread.sleep(2000);
  204. Request request = dialog.createRequest("INVITE");
  205. ((SipURI)request.getRequestURI()).setPort(5080);
  206. final ClientTransaction ct = sipProvider.getNewClientTransaction(request);
  207. dialog.sendRequest(ct);
  208. secondReinviteSent = true;
  209. }
  210. } else if(responseEvent.getResponse().getStatusCode() >= 200 && cSeqHeader.getMethod().equalsIgnoreCase(Request.NOTIFY)) {
  211. notifyTxComplete = true;
  212. Thread.sleep(5000);
  213. Request request = dialog.createRequest("INVITE");
  214. ((SipURI)request.getRequestURI()).setPort(5081);
  215. final ClientTransaction ct = sipProvider.getNewClientTransaction(request);
  216. firstReinviteSent = true;
  217. dialog.sendRequest(ct);
  218. }
  219. } catch (SipException e) {
  220. // TODO Auto-generated catch block
  221. e.printStackTrace();
  222. } catch (InvalidArgumentException e) {
  223. // TODO Auto-generated catch block
  224. e.printStackTrace();
  225. } catch (InterruptedException e) {
  226. // TODO Auto-generated catch block
  227. e.printStackTrace();
  228. }
  229. }
  230. /**
  231. * Process the ACK request. Send the bye and complete the call flow.
  232. */
  233. public void processAck(RequestEvent requestEvent,
  234. ServerTransaction serverTransaction) {
  235. try {
  236. Dialog dialog = serverTransaction.getDialog();
  237. System.out.println("shootme: got an ACK! ");
  238. System.out.println("Dialog State = " + dialog.getState());
  239. firstTxComplete = true;
  240. // used in basic reinvite
  241. if(!firstReinviteSent && !((FromHeader)requestEvent.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI().toString().contains("ReInviteSubsNotify")) {
  242. Thread.sleep(5000);
  243. Request request = dialog.createRequest("INVITE");
  244. ((SipURI)request.getRequestURI()).setPort(5081);
  245. final ClientTransaction ct = sipProvider.getNewClientTransaction(request);
  246. firstReinviteSent = true;
  247. dialog.sendRequest(ct);
  248. }
  249. } catch (Exception ex) {
  250. ex.printStackTrace();
  251. }
  252. }
  253. /**
  254. * Process the invite request.
  255. */
  256. public void processInvite(RequestEvent requestEvent,
  257. ServerTransaction serverTransaction) {
  258. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  259. Request request = requestEvent.getRequest();
  260. try {
  261. System.out.println("shootme: got an Invite sending Trying");
  262. // System.out.println("shootme: " + request);
  263. Response response = messageFactory.createResponse(Response.RINGING,
  264. request);
  265. ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);
  266. toHeader.setTag("4321"); // Application is supposed to set.
  267. ServerTransaction st = requestEvent.getServerTransaction();
  268. if (st == null) {
  269. st = sipProvider.getNewServerTransaction(request);
  270. }
  271. dialog = st.getDialog();
  272. st.sendResponse(response);
  273. Thread.sleep(1000);
  274. this.okResponse = messageFactory.createResponse(Response.OK,
  275. request);
  276. Address address = addressFactory.createAddress("Shootme <sip:"
  277. + myAddress + ":" + myPort + ">");
  278. ContactHeader contactHeader = headerFactory
  279. .createContactHeader(address);
  280. response.addHeader(contactHeader);
  281. toHeader = (ToHeader) okResponse.getHeader(ToHeader.NAME);
  282. toHeader.setTag("4321"); // Application is supposed to set.
  283. okResponse.addHeader(contactHeader);
  284. this.inviteTid = st;
  285. // Defer sending the OK to simulate the phone ringing.
  286. // Answered in 1 second ( this guy is fast at taking calls)
  287. this.inviteRequest = request;
  288. sendInviteOK();
  289. } catch (Exception ex) {
  290. ex.printStackTrace();
  291. System.exit(0);
  292. }
  293. }
  294. private void sendInviteOK() {
  295. try {
  296. if (inviteTid.getState() != TransactionState.COMPLETED) {
  297. System.out.println("shootme: Dialog state before 200: "
  298. + inviteTid.getDialog().getState());
  299. inviteTid.sendResponse(okResponse);
  300. System.out.println("shootme: Dialog state after 200: "
  301. + inviteTid.getDialog().getState());
  302. }
  303. } catch (SipException ex) {
  304. ex.printStackTrace();
  305. } catch (InvalidArgumentException ex) {
  306. ex.printStackTrace();
  307. }
  308. }
  309. /**
  310. * Process the bye request.
  311. */
  312. public void processBye(RequestEvent requestEvent,
  313. ServerTransaction serverTransactionId) {
  314. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  315. Request request = requestEvent.getRequest();
  316. Dialog dialog = requestEvent.getDialog();
  317. System.out.println("local party = " + dialog.getLocalParty());
  318. try {
  319. System.out.println("shootme: got a bye sending OK.");
  320. Response response = messageFactory.createResponse(200, request);
  321. serverTransactionId.sendResponse(response);
  322. System.out.println("Dialog State is "
  323. + serverTransactionId.getDialog().getState());
  324. byeReceived = true;
  325. } catch (Exception ex) {
  326. ex.printStackTrace();
  327. System.exit(0);
  328. }
  329. }
  330. /**
  331. * Process the bye request.
  332. */
  333. public void processSubscribe(RequestEvent requestEvent,
  334. ServerTransaction serverTransactionId) {
  335. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  336. Request request = requestEvent.getRequest();
  337. Dialog dialog = requestEvent.getDialog();
  338. try {
  339. ServerTransaction st = requestEvent.getServerTransaction();
  340. if (st == null) {
  341. st = sipProvider.getNewServerTransaction(request);
  342. }
  343. System.out.println("shootme: got a subscribe sending OK.");
  344. Response response = messageFactory.createResponse(200, request);
  345. response.addHeader(headerFactory.createHeader(ExpiresHeader.NAME, "3600"));
  346. st.sendResponse(response);
  347. System.out.println("Dialog State is "
  348. + st.getDialog().getState());
  349. subscribeTxComplete = true;
  350. Thread.sleep(5000);
  351. Request notify = st.getDialog().createRequest(Request.NOTIFY);
  352. notify.addHeader(headerFactory.createHeader(SubscriptionStateHeader.NAME, SubscriptionStateHeader.ACTIVE));
  353. notify.addHeader(headerFactory.createHeader(EventHeader.NAME, "presence"));
  354. ((SipURI)notify.getRequestURI()).setUser(null);
  355. ((SipURI)notify.getRequestURI()).setHost(IP_ADDRESS);
  356. ((SipURI)notify.getRequestURI()).setPort(5080);
  357. st.getDialog().sendRequest(sipProvider.getNewClientTransaction(notify));
  358. } catch (Exception ex) {
  359. ex.printStackTrace();
  360. System.exit(0);
  361. }
  362. }
  363. public void processCancel(RequestEvent requestEvent,
  364. ServerTransaction serverTransactionId) {
  365. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  366. Request request = requestEvent.getRequest();
  367. try {
  368. System.out.println("shootme: got a cancel.");
  369. if (serverTransactionId == null) {
  370. System.out.println("shootme: null tid.");
  371. return;
  372. }
  373. Response response = messageFactory.createResponse(200, request);
  374. serverTransactionId.sendResponse(response);
  375. if (dialog.getState() != DialogState.CONFIRMED) {
  376. response = messageFactory.createResponse(
  377. Response.REQUEST_TERMINATED, inviteRequest);
  378. inviteTid.sendResponse(response);
  379. }
  380. } catch (Exception ex) {
  381. ex.printStackTrace();
  382. System.exit(0);
  383. }
  384. }
  385. public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
  386. Transaction transaction;
  387. if (timeoutEvent.isServerTransaction()) {
  388. transaction = timeoutEvent.getServerTransaction();
  389. } else {
  390. transaction = timeoutEvent.getClientTransaction();
  391. }
  392. System.out.println("state = " + transaction.getState());
  393. System.out.println("dialog = " + transaction.getDialog());
  394. System.out.println("dialogState = "
  395. + transaction.getDialog().getState());
  396. System.out.println("Transaction Time out");
  397. }
  398. public void init() {
  399. SipFactory sipFactory = null;
  400. sipStack = null;
  401. sipFactory = SipFactory.getInstance();
  402. sipFactory.setPathName("gov.nist");
  403. Properties properties = new Properties();
  404. properties.setProperty("javax.sip.STACK_NAME", stackName);
  405. //properties.setProperty("javax.sip.OUTBOUND_PROXY", Integer
  406. // .toString(BALANCER_PORT));
  407. // You need 16 for logging traces. 32 for debug + traces.
  408. // Your code will limp at 32 but it is best for debugging.
  409. properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
  410. properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "logs/" +
  411. stackName + "debug.txt");
  412. properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "logs/" +
  413. stackName + "log.xml");
  414. try {
  415. // Create SipStack object
  416. sipStack = sipFactory.createSipStack(properties);
  417. System.out.println("sipStack = " + sipStack);
  418. } catch (PeerUnavailableException e) {
  419. // could not find
  420. // gov.nist.jain.protocol.ip.sip.SipStackImpl
  421. // in the classpath
  422. e.printStackTrace();
  423. System.err.println(e.getMessage());
  424. if (e.getCause() != null)
  425. e.getCause().printStackTrace();
  426. System.exit(0);
  427. }
  428. try {
  429. headerFactory = sipFactory.createHeaderFactory();
  430. addressFactory = sipFactory.createAddressFactory();
  431. messageFactory = sipFactory.createMessageFactory();
  432. ListeningPoint lp = sipStack.createListeningPoint(myAddress,
  433. myPort, ListeningPoint.UDP);
  434. Shootme listener = this;
  435. sipProvider = sipStack.createSipProvider(lp);
  436. System.out.println("udp provider " + sipProvider);
  437. sipProvider.addSipListener(listener);
  438. // if(dialogs != null) {
  439. // Collection<Dialog> serializedDialogs = simulateDialogSerialization(dialogs);
  440. // for (Dialog dialog : serializedDialogs) {
  441. // ((SIPDialog)dialog).setSipProvider((SipProviderImpl)sipProvider);
  442. // ((SipStackImpl)sipStack).putDialog((SIPDialog)dialog);
  443. // }
  444. // this.dialog = (SIPDialog)serializedDialogs.iterator().next();
  445. // }
  446. sipStack.start();
  447. if(!callerSendsBye && this.dialog != null) {
  448. try {
  449. Request byeRequest = this.dialog.createRequest(Request.BYE);
  450. ClientTransaction ct = sipProvider.getNewClientTransaction(byeRequest);
  451. System.out.println("sending BYE " + byeRequest);
  452. dialog.sendRequest(ct);
  453. } catch (Exception ex) {
  454. ex.printStackTrace();
  455. fail("Unexpected exception ");
  456. }
  457. }
  458. } catch (Exception ex) {
  459. System.out.println(ex.getMessage());
  460. ex.printStackTrace();
  461. fail("Unexpected exception");
  462. }
  463. }
  464. private Collection<Dialog> simulateDialogSerialization(
  465. Collection<Dialog> dialogs) {
  466. Collection<Dialog> serializedDialogs = new ArrayList<Dialog>();
  467. for (Dialog dialog : dialogs) {
  468. try{
  469. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  470. ObjectOutputStream out = new ObjectOutputStream(baos);
  471. out.writeObject(dialog);
  472. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  473. ObjectInputStream in =new ObjectInputStream(bais);
  474. SIPDialog serializedDialog = (SIPDialog)in.readObject();
  475. serializedDialogs.add(serializedDialog);
  476. out.close();
  477. in.close();
  478. baos.close();
  479. bais.close();
  480. } catch (IOException e) {
  481. e.printStackTrace();
  482. } catch (ClassNotFoundException e) {
  483. e.printStackTrace();
  484. }
  485. }
  486. return serializedDialogs;
  487. }
  488. public void processIOException(IOExceptionEvent exceptionEvent) {
  489. System.out.println("IOException");
  490. }
  491. public void processTransactionTerminated(
  492. TransactionTerminatedEvent transactionTerminatedEvent) {
  493. if (transactionTerminatedEvent.isServerTransaction())
  494. System.out.println("Transaction terminated event recieved"
  495. + transactionTerminatedEvent.getServerTransaction());
  496. else
  497. System.out.println("Transaction terminated "
  498. + transactionTerminatedEvent.getClientTransaction());
  499. }
  500. public void processDialogTerminated(
  501. DialogTerminatedEvent dialogTerminatedEvent) {
  502. System.out.println("Dialog terminated event recieved");
  503. Dialog d = dialogTerminatedEvent.getDialog();
  504. System.out.println("Local Party = " + d.getLocalParty());
  505. }
  506. public void stop() {
  507. stopSipStack(sipStack, this);
  508. }
  509. public void checkState(boolean reinviteSubsNotify) {
  510. if(reinviteSubsNotify) {
  511. if(firstTxComplete && subscribeTxComplete && notifyTxComplete && firstReInviteComplete && secondReInviteComplete && byeReceived) {
  512. System.out.println("shootme state OK " );
  513. } else {
  514. fail("firstTxComplete " + firstTxComplete + " && subscribeTxComplete " + subscribeTxComplete + " && notifyComplete " + notifyTxComplete + " && firstReInviteComplete " + firstReInviteComplete + "&& secondReInviteComplete " + secondReInviteComplete + " && byeReceived " + byeReceived);
  515. }
  516. } else {
  517. if(firstTxComplete && firstReInviteComplete && secondReInviteComplete && byeReceived) {
  518. System.out.println("shootme state OK " );
  519. } else {
  520. fail("firstTxComplete " + firstTxComplete + " && firstReInviteComplete " + firstReInviteComplete + "&& secondReInviteComplete " + secondReInviteComplete + " && byeReceived " + byeReceived);
  521. }
  522. }
  523. }
  524. }
  525. class Shootist implements SipListener {
  526. private SipProvider sipProvider;
  527. private SipStack sipStack;
  528. private ContactHeader contactHeader;
  529. private ListeningPoint udpListeningPoint;
  530. private ClientTransaction inviteTid;
  531. private Dialog dialog;
  532. private boolean byeTaskRunning;
  533. public boolean callerSendsBye = true;
  534. private static final String myAddress = IP_ADDRESS;
  535. public int myPort = 5050;
  536. private boolean sendSubscribe ;
  537. private boolean firstTxComplete;
  538. private boolean firstReInviteComplete;
  539. private boolean secondReInviteComplete;
  540. private boolean thirdReInviteComplete;
  541. private boolean okToByeReceived;
  542. // Save the created ACK request, to respond to retransmitted 2xx
  543. private Request ackRequest;
  544. private boolean notifyTxComplete;
  545. private boolean subscribeTxComplete;
  546. private String stackName;
  547. class ByeTask extends TimerTask {
  548. Dialog dialog;
  549. public ByeTask(Dialog dialog) {
  550. this.dialog = dialog;
  551. }
  552. public void run () {
  553. try {
  554. Request byeRequest = this.dialog.createRequest(Request.BYE);
  555. ClientTransaction ct = sipProvider.getNewClientTransaction(byeRequest);
  556. dialog.sendRequest(ct);
  557. } catch (Exception ex) {
  558. ex.printStackTrace();
  559. fail("Unexpected exception ");
  560. }
  561. }
  562. }
  563. public Shootist(String stackName, boolean callerSendsBye) {
  564. this.callerSendsBye = callerSendsBye;
  565. this.stackName = stackName;
  566. }
  567. public void processRequest(RequestEvent requestReceivedEvent) {
  568. Request request = requestReceivedEvent.getRequest();
  569. ServerTransaction serverTransactionId = requestReceivedEvent
  570. .getServerTransaction();
  571. System.out.println("\n\nRequest " + request.getMethod()
  572. + " received at " + sipStack.getStackName()
  573. + " with server transaction id " + serverTransactionId);
  574. // We are the UAC so the only request we get is the BYE.
  575. if (request.getMethod().equals(Request.BYE))
  576. processBye(request, serverTransactionId);
  577. else if(request.getMethod().equals(Request.NOTIFY)) {
  578. try {
  579. serverTransactionId.sendResponse( messageFactory.createResponse(200,request) );
  580. notifyTxComplete = true;
  581. } catch (Exception e) {
  582. e.printStackTrace();
  583. fail("Unxepcted exception ");
  584. }
  585. } else {
  586. if(!request.getMethod().equals(Request.ACK)) {
  587. // not used in basic reinvite
  588. if(((CSeqHeader) request.getHeader(CSeqHeader.NAME)).getSeqNumber() == 1 && ((ToHeader)request.getHeader(ToHeader.NAME)).getAddress().getURI().toString().contains("ReInviteSubsNotify")) {
  589. try {
  590. serverTransactionId.sendResponse( messageFactory.createResponse(202,request) );
  591. } catch (Exception e) {
  592. e.printStackTrace();
  593. fail("Unxepcted exception ");
  594. }
  595. } else {
  596. processInvite(requestReceivedEvent, serverTransactionId);
  597. }
  598. } else {
  599. if(request.getMethod().equals(Request.ACK)) {
  600. long cseq = ((CSeqHeader) request.getHeader(CSeqHeader.NAME)).getSeqNumber();
  601. switch ((int) cseq) {
  602. case 1:
  603. firstReInviteComplete = true;
  604. // not used in basic reinvite
  605. if(sendSubscribe) {
  606. try {
  607. Request subscribe = requestReceivedEvent.getDialog().createRequest(Request.SUBSCRIBE);
  608. requestReceivedEvent.getDialog().sendRequest(sipProvider.getNewClientTransaction(subscribe));
  609. } catch (SipException e) {
  610. // TODO Auto-generated catch block
  611. e.printStackTrace();
  612. fail("Unxepcted exception ");
  613. }
  614. }
  615. break;
  616. case 2:
  617. secondReInviteComplete = true;
  618. break;
  619. case 3:
  620. secondReInviteComplete = true;
  621. break;
  622. case 4:
  623. thirdReInviteComplete = true;
  624. break;
  625. default:
  626. break;
  627. }
  628. }
  629. }
  630. }
  631. }
  632. /**
  633. * Process the invite request.
  634. */
  635. public void processInvite(RequestEvent requestEvent,
  636. ServerTransaction serverTransaction) {
  637. SipProvider sipProvider = (SipProvider) requestEvent.getSource();
  638. Request request = requestEvent.getRequest();
  639. if(!((ToHeader)requestEvent.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI().toString().contains("ReInvite") && !((FromHeader)requestEvent.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI().toString().contains("LittleGuy")) {
  640. throw new IllegalStateException("The From and To Headers are reversed !!!!");
  641. }
  642. try {
  643. System.out.println("shootme: got an Invite sending Trying");
  644. // System.out.println("shootme: " + request);
  645. Response response = messageFactory.createResponse(Response.RINGING,
  646. request);
  647. ServerTransaction st = requestEvent.getServerTransaction();
  648. if (st == null) {
  649. st = sipProvider.getNewServerTransaction(request);
  650. }
  651. dialog = st.getDialog();
  652. st.sendResponse(response);
  653. Thread.sleep(1000);
  654. Response okResponse = messageFactory.createResponse(Response.OK,
  655. request);
  656. Address address = addressFactory.createAddress("Shootme <sip:"
  657. + myAddress + ":" + myPort + ">");
  658. ContactHeader contactHeader = headerFactory
  659. .createContactHeader(address);
  660. response.addHeader(contactHeader);
  661. okResponse.addHeader(contactHeader);
  662. // this.inviteTid = st;
  663. // Defer sending the OK to simulate the phone ringing.
  664. // Answered in 1 second ( this guy is fast at taking calls)
  665. // this.inviteRequest = request;
  666. if (inviteTid.getState() != TransactionState.COMPLETED) {
  667. System.out.println("shootme: Dialog state before 200: "
  668. + inviteTid.getDialog().getState());
  669. st.sendResponse(okResponse);
  670. System.out.println("shootme: Dialog state after 200: "
  671. + inviteTid.getDialog().getState());
  672. }
  673. } catch (Exception ex) {
  674. ex.printStackTrace();
  675. System.exit(0);
  676. }
  677. }
  678. public void processBye(Request request,
  679. ServerTransaction serverTransactionId) {
  680. try {
  681. System.out.println("shootist: got a bye .");
  682. if (serverTransactionId == null) {
  683. System.out.println("shootist: null TID.");
  684. return;
  685. }
  686. Dialog dialog = serverTransactionId.getDialog();
  687. System.out.println("Dialog State = " + dialog.getState());
  688. Response response = messageFactory.createResponse(200, request);
  689. serverTransactionId.sendResponse(response);
  690. System.out.println("shootist: Sending OK.");
  691. System.out.println("Dialog State = " + dialog.getState());
  692. } catch (Exception ex) {
  693. fail("Unexpected exception");
  694. }
  695. }
  696. public void processResponse(ResponseEvent responseReceivedEvent) {
  697. System.out.println("Got a response");
  698. Response response = (Response) responseReceivedEvent.getResponse();
  699. ClientTransaction tid = responseReceivedEvent.getClientTransaction();
  700. CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
  701. System.out.println("Response received : Status Code = "
  702. + response.getStatusCode() + " " + cseq);
  703. if(cseq.getMethod().equalsIgnoreCase(Request.SUBSCRIBE)) {
  704. subscribeTxComplete = true;
  705. return;
  706. }
  707. if (tid == null) {
  708. // RFC3261: MUST respond to every 2xx
  709. if (ackRequest!=null && dialog!=null) {
  710. System.out.println("re-sending ACK");
  711. try {
  712. dialog.sendAck(ackRequest);
  713. } catch (SipException se) {
  714. se.printStackTrace();
  715. fail("Unxpected exception ");
  716. }
  717. }
  718. return;
  719. }
  720. // If the caller is supposed to send the bye
  721. if ( callerSendsBye && !byeTaskRunning) {
  722. byeTaskRunning = true;
  723. new Timer().schedule(new ByeTask(dialog), 50000) ;
  724. }
  725. System.out.println("transaction state is " + tid.getState());
  726. System.out.println("Dialog = " + tid.getDialog());
  727. System.out.println("Dialog State is " + tid.getDialog().getState());
  728. assertSame("Checking dialog identity",tid.getDialog(), this.dialog);
  729. try {
  730. if (response.getStatusCode() == Response.OK) {
  731. if (cseq.getMethod().equals(Request.INVITE)) {
  732. System.out.println("Dialog after 200 OK " + dialog);
  733. System.out.println("Dialog State after 200 OK " + dialog.getState());
  734. Request ackRequest = dialog.createAck(cseq.getSeqNumber());
  735. System.out.println("Sending ACK");
  736. dialog.sendAck(ackRequest);
  737. firstTxComplete = true;
  738. // JvB: test REFER, reported bug in tag handling
  739. // Request referRequest = dialog.createRequest("REFER");
  740. // //simulating a balancer that will forward the request to the recovery node
  741. // SipURI referRequestURI = addressFactory.createSipURI(null, "127.0.0.1:5080");
  742. // referRequest.setRequestURI(referRequestURI);
  743. // dialog.sendRequest( sipProvider.getNewClientTransaction(referRequest));
  744. //
  745. } else if (cseq.getMethod().equals(Request.CANCEL)) {
  746. if (dialog.getState() == DialogState.CONFIRMED) {
  747. // oops cancel went in too late. Need to hang up the
  748. // dialog.
  749. System.out
  750. .println("Sending BYE -- cancel went in too late !!");
  751. Request byeRequest = dialog.createRequest(Request.BYE);
  752. ClientTransaction ct = sipProvider
  753. .getNewClientTransaction(byeRequest);
  754. dialog.sendRequest(ct);
  755. }
  756. } else if (cseq.getMethod().equals(Request.BYE)) {
  757. okToByeReceived = true;
  758. }
  759. }
  760. } catch (Exception ex) {
  761. ex.printStackTrace();
  762. System.exit(0);
  763. }
  764. }
  765. public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
  766. System.out.println("Transaction Time out");
  767. }
  768. public void sendCancel() {
  769. try {
  770. System.out.println("Sending cancel");
  771. Request cancelRequest = inviteTid.createCancel();
  772. ClientTransaction cancelTid = sipProvider
  773. .getNewClientTransaction(cancelRequest);
  774. cancelTid.sendRequest();
  775. } catch (Exception ex) {
  776. ex.printStackTrace();
  777. }
  778. }
  779. public void init(String from) {
  780. SipFactory sipFactory = null;
  781. sipStack = null;
  782. sipFactory = SipFactory.getInstance();
  783. sipFactory.setPathName("gov.nist");
  784. Properties properties = new Properties();
  785. // If you want to try TCP transport change the following to
  786. String transport = "udp";
  787. String peerHostPort = IP_ADDRESS + ":" + 5080;
  788. //properties.setProperty("javax.sip.OUTBOUND_PROXY", peerHostPort + "/"
  789. // + transport);
  790. // If you want to use UDP then uncomment this.
  791. properties.setProperty("javax.sip.STACK_NAME", stackName);
  792. // The following properties are specific to nist-sip
  793. // and are not necessarily part of any other jain-sip
  794. // implementation.
  795. // You can set a max message size for tcp transport to
  796. // guard against denial of service attack.
  797. properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
  798. "logs/shootistdebug.txt");
  799. properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
  800. "logs/shootistlog.xml");
  801. // Drop the client connection after we are done with the transaction.
  802. properties.setProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS",
  803. "false");
  804. // Set to 0 (or NONE) in your production code for max speed.
  805. // You need 16 (or TRACE) for logging traces. 32 (or DEBUG) for debug + traces.
  806. // Your code will limp at 32 but it is best for debugging.
  807. properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "DEBUG");
  808. try {
  809. // Create SipStack object
  810. sipStack = sipFactory.createSipStack(properties);
  811. System.out.println("createSipStack " + sipStack);
  812. } catch (PeerUnavailableException e) {
  813. // could not find
  814. // gov.nist.jain.protocol.ip.sip.SipStackImpl
  815. // in the classpath
  816. e.printStackTrace();
  817. System.err.println(e.getMessage());
  818. System.exit(0);
  819. }
  820. try {
  821. headerFactory = sipFactory.createHeaderFactory();
  822. addressFactory = sipFactory.createAddressFactory();
  823. messageFactory = sipFactory.createMessageFactory();
  824. udpListeningPoint = sipStack.createListeningPoint(IP_ADDRESS, myPort, "udp");
  825. sipProvider = sipStack.createSipProvider(udpListeningPoint);
  826. Shootist listener = this;
  827. sipProvider.addSipListener(listener);
  828. String fromName = from;
  829. String fromSipAddress = "here.com";
  830. String fromDisplayName = "The Master Blaster";
  831. String toSipAddress = "there.com";
  832. String toUser = "LittleGuy";
  833. String toDisplayName = "The Little Blister";
  834. // create >From Header
  835. SipURI fromAddress = addressFactory.createSipURI(fromName,
  836. fromSipAddress);
  837. Address fromNameAddress = addressFactory.createAddress(fromAddress);
  838. fromNameAddress.setDisplayName(fromDisplayName);
  839. FromHeader fromHeader = headerFactory.createFromHeader(
  840. fromNameAddress, "12345");
  841. // create To Header
  842. SipURI toAddress = addressFactory
  843. .createSipURI(toUser, toSipAddress);
  844. Address toNameAddress = addressFactory.createAddress(toAddress);
  845. toNameAddress.setDisplayName(toDisplayName);
  846. ToHeader toHeader = headerFactory.createToHeader(toNameAddress,
  847. null);
  848. // create Request URI
  849. SipURI requestURI = addressFactory.createSipURI(toUser,
  850. peerHostPort);
  851. // Create ViaHeaders
  852. ArrayList viaHeaders = new ArrayList();
  853. String ipAddress = udpListeningPoint.getIPAddress();
  854. ViaHeader viaHeader = headerFactory.createViaHeader(ipAddress,
  855. sipProvider.getListeningPoint(transport).getPort(),
  856. transport, null);
  857. // add via headers
  858. viaHeaders.add(viaHeader);
  859. // Create ContentTypeHeader
  860. ContentTypeHeader contentTypeHeader = headerFactory
  861. .createContentTypeHeader("application", "sdp");
  862. // Create a new CallId header
  863. CallIdHeader callIdHeader = sipProvider.getNewCallId();
  864. // Create a new Cseq header
  865. CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L,
  866. Request.INVITE);
  867. // Create a new MaxForwardsHeader
  868. MaxForwardsHeader maxForwards = headerFactory
  869. .createMaxForwardsHeader(70);
  870. // Create the request.
  871. Request request = messageFactory.createRequest(requestURI,
  872. Request.INVITE, callIdHeader, cSeqHeader, fromHeader,
  873. toHeader, viaHeaders, maxForwards);
  874. // Create contact headers
  875. String host = IP_ADDRESS;
  876. SipURI contactUrl = addressFactory.createSipURI(fromName, host);
  877. contactUrl.setPort(udpListeningPoint.getPort());
  878. contactUrl.setLrParam();
  879. // Create the contact name address.
  880. SipURI contactURI = addressFactory.createSipURI(fromName, host);
  881. contactURI.setPort(sipProvider.getListeningPoint(transport)
  882. .getPort());
  883. Address contactAddress = addressFactory.createAddress(contactURI);
  884. // Add the contact address.
  885. contactAddress.setDisplayName(fromName);
  886. contactHeader = headerFactory.createContactHeader(contactAddress);
  887. request.addHeader(contactHeader);
  888. // You can add extension headers of your own making
  889. // to the outgoing SIP request.
  890. // Add the extension header.
  891. Header extensionHeader = headerFactory.createHeader("My-Header",
  892. "my header value");
  893. request.addHeader(extensionHeader);
  894. String sdpData = "v=0\r\n"
  895. + "o=4855 13760799956958020 13760799956958020"
  896. + " IN IP4 129.6.55.78\r\n" + "s=mysession session\r\n"
  897. + "p=+46 8 52018010\r\n" + "c=IN IP4 129.6.55.78\r\n"
  898. + "t=0 0\r\n" + "m=audio 6022 RTP/AVP 0 4 18\r\n"
  899. + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:4 G723/8000\r\n"
  900. + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n";
  901. byte[] contents = sdpData.getBytes();
  902. request.setContent(contents, contentTypeHeader);
  903. // You can add as many extension headers as you
  904. // want.
  905. extensionHeader = headerFactory.createHeader("My-Other-Header",
  906. "my new header value ");
  907. request.addHeader(extensionHeader);
  908. Header callInfoHeader = headerFactory.createHeader("Call-Info",
  909. "<http://www.antd.nist.gov>");
  910. request.addHeader(callInfoHeader);
  911. // Create the client transaction.
  912. inviteTid = sipProvider.getNewClientTransaction(request);
  913. // send the request out.
  914. inviteTid.sendRequest();
  915. dialog = inviteTid.getDialog();
  916. } catch (Exception ex) {
  917. System.out.println(ex.getMessage());
  918. ex.printStackTrace();
  919. fail("Unxpected exception ");
  920. }
  921. }
  922. public void processIOException(IOExceptionEvent exceptionEvent) {
  923. System.out.println("IOException happened for "
  924. + exceptionEvent.getHost() + " port = "
  925. + exceptionEvent.getPort());
  926. }
  927. public void processTransactionTerminated(
  928. TransactionTerminatedEvent transactionTerminatedEvent) {
  929. System.out.println("Transaction terminated event recieved");
  930. }
  931. public void processDialogTerminated(
  932. DialogTerminatedEvent dialogTerminatedEvent) {
  933. System.out.println("dialogTerminatedEvent");
  934. }
  935. public void stop() {
  936. stopSipStack(sipStack, this);
  937. }
  938. public void checkState(boolean reinviteSubsNotify) {
  939. if(reinviteSubsNotify) {
  940. if(firstTxComplete && firstReInviteComplete && subscribeTxComplete && notifyTxComplete && secondReInviteComplete && thirdReInviteComplete && okToByeReceived) {
  941. System.out.println("shootist state OK " );
  942. } else {
  943. fail("firstTxComplete " + firstTxComplete + " && firstReInviteComplete " + firstReInviteComplete + " && subscribeTxComplete " + subscribeTxComplete + " && notifyComplete " + notifyTxComplete + "&& secondReInviteComplete " + secondReInviteComplete + "&& thirdReInviteComplete " + thirdReInviteComplete + " && okToByeReceived " + okToByeReceived);
  944. }
  945. } else {
  946. if(firstTxComplete && firstReInviteComplete && secondReInviteComplete && okToByeReceived) {
  947. System.out.println("shootist state OK " );
  948. } else {
  949. fail("firstTxComplete " + firstTxComplete + " && firstReInviteComplete " + firstReInviteComplete + " && secondReInviteComplete " + secondReInviteComplete + " && okToByeReceived " + okToByeReceived);
  950. }
  951. }
  952. }
  953. public void setSendSubscribe(boolean b) {
  954. sendSubscribe = b;
  955. }
  956. }
  957. public static void stopSipStack(SipStack sipStack, SipListener listener) {
  958. Iterator<SipProvider> sipProviderIterator = sipStack.getSipProviders();
  959. try{
  960. while (sipProviderIterator.hasNext()) {
  961. SipProvider sipProvider = sipProviderIterator.next();
  962. ListeningPoint[] listeningPoints = sipProvider.getListeningPoints();
  963. for (ListeningPoint listeningPoint : listeningPoints) {
  964. sipProvider.removeListeningPoint(listeningPoint);
  965. sipStack.deleteListeningPoint(listeningPoint);
  966. listeningPoints = sipProvider.getListeningPoints();
  967. }
  968. sipProvider.removeSipListener(listener);
  969. sipStack.deleteSipProvider(sipProvider);
  970. sipProviderIterator = sipStack.getSipProviders();
  971. }
  972. } catch (Exception e) {
  973. throw new IllegalStateException("Cant remove the listening points or sip providers", e);
  974. }
  975. sipStack.stop();
  976. sipStack = null;
  977. }
  978. /**
  979. * UA1 B2BUA (Engine1) B2BUA (Engine2) UA2
  980. * INVITE (CSeq 1)
  981. * ----------------------->
  982. *
  983. * INVITE (CSeq 1)
  984. * ------------------------------------------------->
  985. * INVITE (CSeq 1)
  986. * <------------------------
  987. *
  988. * SUBSCRIBE(CSeq 2)
  989. * ----------------------->
  990. *
  991. * SUBSCRIBE (CSeq 2)
  992. * ------------------------------------------------->
  993. *
  994. * NOTIFY (CSeq 1)
  995. * <-------------------------------------------------
  996. * NOTIFY (CSeq 2)
  997. * <------------------------
  998. *
  999. * INVITE (CSeq 2)
  1000. * <---------------------
  1001. * INVITE (CSeq 3)
  1002. * <------------------------------------------
  1003. * INVITE (CSeq 3)
  1004. * <----------------------------------------
  1005. * INVITE (CSeq 4)
  1006. * <---------------------
  1007. * BYE (CSeq 3)
  1008. * ----------------------->
  1009. * BYE (CSeq 3)
  1010. * ------------------------------------->
  1011. */
  1012. public void testDialogFailoverReInviteSubsNotify() throws Exception {
  1013. shootist = new Shootist("shootist_subsnotify", true);
  1014. shootme = new Shootme("shootme_subsnotify", 5070, true);
  1015. b2buaNode1 = new SimpleB2BUA("b2buaNode1_subsnotify", 5080, IP_ADDRESS, ListeningPoint.UDP, ReplicationStrategy.ConfirmedDialogNoApplicationData, false);
  1016. Thread.sleep(5000);
  1017. b2buaNode2 = new SimpleB2BUA("b2buaNode2_subsnotify", 5081, IP_ADDRESS, ListeningPoint.UDP, ReplicationStrategy.ConfirmedDialogNoApplicationData, false);
  1018. shootme.init();
  1019. shootist.setSendSubscribe(true);
  1020. shootist.init("ReInviteSubsNotify");
  1021. Thread.sleep(60000);
  1022. shootme.checkState(true);
  1023. shootist.checkState(true);
  1024. // make sure dialogs are removed on both nodes

Large files files are truncated, but you can click here to view the full file