PageRenderTime 33ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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