PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/jain-sip-ha/core/src/main/java/gov/nist/javax/sip/stack/AbstractHASipDialog.java

http://mobicents.googlecode.com/
Java | 670 lines | 548 code | 37 blank | 85 comment | 146 complexity | 041c68f06cd6f342933844a866ec794a 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 gov.nist.javax.sip.stack;
  23. import gov.nist.core.CommonLogger;
  24. import gov.nist.core.StackLogger;
  25. import gov.nist.javax.sip.SipProviderImpl;
  26. import gov.nist.javax.sip.header.Contact;
  27. import gov.nist.javax.sip.header.Route;
  28. import gov.nist.javax.sip.header.RouteList;
  29. import gov.nist.javax.sip.header.SIPHeader;
  30. import gov.nist.javax.sip.message.SIPResponse;
  31. import gov.nist.javax.sip.parser.EventParser;
  32. import java.text.ParseException;
  33. import java.util.ArrayList;
  34. import java.util.HashMap;
  35. import java.util.Iterator;
  36. import java.util.List;
  37. import java.util.Map;
  38. import java.util.concurrent.atomic.AtomicLong;
  39. import javax.sip.DialogState;
  40. import javax.sip.PeerUnavailableException;
  41. import javax.sip.ServerTransaction;
  42. import javax.sip.SipException;
  43. import javax.sip.SipFactory;
  44. import javax.sip.address.Address;
  45. import javax.sip.address.AddressFactory;
  46. import javax.sip.header.ContactHeader;
  47. import javax.sip.header.EventHeader;
  48. import javax.sip.header.HeaderFactory;
  49. import org.mobicents.ha.javax.sip.ClusteredSipStack;
  50. import org.mobicents.ha.javax.sip.HASipDialog;
  51. import org.mobicents.ha.javax.sip.ReplicationStrategy;
  52. /**
  53. * @author jean.deruelle@gmail.com
  54. *
  55. */
  56. public abstract class AbstractHASipDialog extends SIPDialog implements HASipDialog {
  57. private static StackLogger logger = CommonLogger.getLogger(AbstractHASipDialog.class);
  58. private static final long serialVersionUID = 1L;
  59. public static final String B2BUA = "b2b";
  60. public static final String EVENT_HEADER = "eh";
  61. public static final String REMOTE_TARGET = "rt";
  62. public static final String TERMINATE_ON_BYE = "tob";
  63. public static final String ROUTE_LIST = "rl";
  64. public static final String IS_REINVITE = "ir";
  65. public static final String LAST_RESPONSE = "lr";
  66. public static final String IS_SERVER = "is";
  67. public static final String IS_LATEST_TX_SERVER = "ilts";
  68. public static final String FIRST_TX_METHOD = "ftm";
  69. public static final String FIRST_TX_ID = "ftid";
  70. public static final String FIRST_TX_PORT = "ftp";
  71. public static final String FIRST_TX_SECURE = "fts";
  72. public static final String CONTACT_HEADER = "ch";
  73. public static final String LOCAL_TAG = "ltag";
  74. public static final String REMOTE_TAG = "rtag";
  75. public static final String VERSION = "v";
  76. public static final String REMOTE_CSEQ = "rc";
  77. public static final String LOCAL_CSEQ = "lc";
  78. public static final String DIALOG_METHOD = "dm";
  79. public static final String ENABLE_CSEQ_VALIDATION = "dc";
  80. public static final String DIALOG_STATE = "ds";
  81. public boolean b2buaChanged;
  82. public boolean eventChanged;
  83. public boolean remoteTargetChanged;
  84. public boolean terminateOnByeChanged;
  85. public boolean isReinviteChanged;
  86. public boolean storeFirstTxChanged;
  87. public boolean dialogStateChanged;
  88. public boolean isLatestTxServer;
  89. static AddressFactory addressFactory = null;
  90. static HeaderFactory headerFactory = null;
  91. boolean isCreated = false;
  92. private AtomicLong version = new AtomicLong(0);
  93. private String lastResponseStringified = null;
  94. static {
  95. try {
  96. headerFactory = SipFactory.getInstance().createHeaderFactory();
  97. addressFactory = SipFactory.getInstance().createAddressFactory();
  98. } catch (PeerUnavailableException e) {}
  99. }
  100. public AbstractHASipDialog(SIPTransaction transaction) {
  101. super(transaction);
  102. isCreated = true;
  103. }
  104. public AbstractHASipDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {
  105. super(transaction, sipResponse);
  106. isCreated = true;
  107. }
  108. public AbstractHASipDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) {
  109. super(sipProvider, sipResponse);
  110. isCreated = true;
  111. }
  112. /**
  113. * Updates the local dialog transient attributes that were not serialized during the replication
  114. * @param sipStackImpl the sip Stack Impl that reloaded this dialog from the distributed cache
  115. */
  116. public void initAfterLoad(ClusteredSipStack sipStackImpl) {
  117. String transport = getLastResponseTopMostVia().getTransport();
  118. Iterator<SipProviderImpl> providers = sipStackImpl.getSipProviders();
  119. boolean providerNotFound = true;
  120. while(providers.hasNext()) {
  121. SipProviderImpl providerImpl = providers.next();
  122. if(providerImpl.getListeningPoint(transport) != null) {
  123. setSipProvider(providerImpl);
  124. providerNotFound = false;
  125. }
  126. }
  127. if(providerNotFound) {
  128. throw new RuntimeException("No providers found for transport="
  129. + transport + " on this node. Make sure connectors are configured for this transport");
  130. }
  131. setStack((SIPTransactionStack)sipStackImpl);
  132. setAssigned();
  133. firstTransactionPort = getSipProvider().getListeningPoint(getLastResponseTopMostVia().getTransport()).getPort();
  134. ackProcessed = true;
  135. // ackSeen = true;
  136. }
  137. @SuppressWarnings("unchecked")
  138. public Map<String,Object> getMetaDataToReplicate() {
  139. Map<String,Object> dialogMetaData = new HashMap<String,Object>();
  140. dialogMetaData.put(VERSION, Long.valueOf(version.incrementAndGet()));
  141. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  142. logger.logDebug(getDialogIdToReplicate() + " : version " + version);
  143. }
  144. if(dialogStateChanged) {
  145. dialogMetaData.put(DIALOG_STATE, Integer.valueOf(getState().getValue()));
  146. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  147. logger.logDebug(getDialogIdToReplicate() + " : dialogState " + getState());
  148. }
  149. dialogStateChanged = false;
  150. }
  151. boolean firstTimeReplication = version.get() == 1;
  152. if(firstTimeReplication) {
  153. dialogMetaData.put(DIALOG_METHOD, getMethod());
  154. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  155. logger.logDebug(getDialogIdToReplicate() + " : dialog method " + getMethod());
  156. }
  157. }
  158. dialogMetaData.put(LAST_RESPONSE, getLastResponseStringified());
  159. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  160. logger.logDebug(getDialogIdToReplicate() + " : lastResponse " + getLastResponseStringified());
  161. }
  162. if(isReinviteChanged) {
  163. dialogMetaData.put(IS_REINVITE, isReInvite());
  164. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  165. logger.logDebug(getDialogIdToReplicate() + " : isReInvite " + isReInvite());
  166. }
  167. isReinviteChanged = false;
  168. }
  169. final List<SIPHeader> routeList = new ArrayList<SIPHeader>();
  170. final Iterator<SIPHeader> it = getRouteSet();
  171. while (it.hasNext()) {
  172. SIPHeader sipHeader = (SIPHeader) it.next();
  173. routeList.add(sipHeader);
  174. }
  175. final String[] routes = new String[routeList.size()];
  176. int i = 0;
  177. for (SIPHeader sipHeader : routeList) {
  178. routes[i++] = sipHeader.getHeaderValue().toString();
  179. }
  180. dialogMetaData.put(ROUTE_LIST, routes);
  181. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  182. logger.logDebug(getDialogIdToReplicate() + " : routes " + routes);
  183. }
  184. if(terminateOnByeChanged) {
  185. dialogMetaData.put(TERMINATE_ON_BYE, Boolean.valueOf(isTerminatedOnBye()));
  186. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  187. logger.logDebug(getDialogIdToReplicate() + " : terminateOnBye " + isTerminatedOnBye());
  188. }
  189. terminateOnByeChanged = false;
  190. }
  191. if(remoteTargetChanged) {
  192. if(getRemoteTarget() != null) {
  193. dialogMetaData.put(REMOTE_TARGET, getRemoteTarget().toString());
  194. } else {
  195. dialogMetaData.put(REMOTE_TARGET, null);
  196. }
  197. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  198. logger.logDebug(getDialogIdToReplicate() + " : remoteTarget " + getRemoteTarget());
  199. }
  200. remoteTargetChanged = false;
  201. }
  202. if(eventChanged) {
  203. if(getEventHeader() != null) {
  204. dialogMetaData.put(EVENT_HEADER, getEventHeader().toString());
  205. } else {
  206. dialogMetaData.put(EVENT_HEADER, null);
  207. }
  208. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  209. logger.logDebug(getDialogIdToReplicate() + " : evenHeader " + getEventHeader());
  210. }
  211. eventChanged = false;
  212. }
  213. if(b2buaChanged) {
  214. dialogMetaData.put(B2BUA, Boolean.valueOf(isBackToBackUserAgent()));
  215. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  216. logger.logDebug(getDialogIdToReplicate() + " : isB2BUA " + isBackToBackUserAgent());
  217. }
  218. b2buaChanged = false;
  219. }
  220. if(storeFirstTxChanged) {
  221. dialogMetaData.put(IS_SERVER, Boolean.valueOf(isServer()));
  222. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  223. logger.logDebug(getDialogIdToReplicate() + " : isServer " + isServer());
  224. }
  225. dialogMetaData.put(FIRST_TX_SECURE, Boolean.valueOf(firstTransactionSecure));
  226. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  227. logger.logDebug(getDialogIdToReplicate() + " : firstTxSecure " + firstTransactionSecure);
  228. }
  229. dialogMetaData.put(FIRST_TX_ID, firstTransactionId);
  230. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  231. logger.logDebug(getDialogIdToReplicate() + " : firstTransactionId " + firstTransactionId);
  232. }
  233. dialogMetaData.put(ENABLE_CSEQ_VALIDATION, isSequnceNumberValidation());
  234. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  235. logger.logDebug(getDialogIdToReplicate() + " : CSeq validation is " + isSequnceNumberValidation());
  236. }
  237. dialogMetaData.put(FIRST_TX_METHOD, firstTransactionMethod);
  238. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  239. logger.logDebug(getDialogIdToReplicate() + " : firstTransactionMethod " + firstTransactionMethod);
  240. }
  241. if(contactHeader != null) {
  242. dialogMetaData.put(CONTACT_HEADER, contactHeader.toString());
  243. }
  244. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  245. logger.logDebug(getDialogIdToReplicate() + " : contactHeader " + contactHeader);
  246. }
  247. storeFirstTxChanged = false;
  248. }
  249. dialogMetaData.put(IS_LATEST_TX_SERVER, Boolean.valueOf(isLatestTxServer));
  250. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  251. logger.logDebug(getDialogIdToReplicate() + " : isLatestTxServer " + isLatestTxServer);
  252. }
  253. dialogMetaData.put(REMOTE_TAG, getRemoteTag());
  254. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  255. logger.logDebug(getDialogIdToReplicate() + " : remoteTag " + getRemoteTag());
  256. }
  257. dialogMetaData.put(LOCAL_TAG, getLocalTag());
  258. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  259. logger.logDebug(getDialogIdToReplicate() + " : localTag " + getLocalTag());
  260. }
  261. dialogMetaData.put(REMOTE_CSEQ, Long.valueOf(getRemoteSeqNumber()));
  262. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  263. logger.logDebug(getDialogIdToReplicate() + " : remoteCSeq " + getRemoteSeqNumber());
  264. }
  265. dialogMetaData.put(LOCAL_CSEQ, Long.valueOf(getLocalSeqNumber()));
  266. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  267. logger.logDebug(getDialogIdToReplicate() + " : localCSeq " + getLocalSeqNumber());
  268. }
  269. return dialogMetaData;
  270. }
  271. public Object getApplicationDataToReplicate() {
  272. return getApplicationData();
  273. }
  274. public void setMetaDataToReplicate(Map<String, Object> metaData, boolean recreation) {
  275. final ReplicationStrategy replicationStrategy = ((ClusteredSipStack)getStack()).getReplicationStrategy();
  276. if(replicationStrategy == ReplicationStrategy.EarlyDialog) {
  277. Integer dialogState = (Integer) metaData.get(DIALOG_STATE);
  278. if(dialogState!= null) {
  279. // the call to super is very important otherwise it triggers replication on dialog recreation
  280. super.setState(dialogState);
  281. }
  282. } else {
  283. // the call to super is very important otherwise it triggers replication on dialog recreation
  284. super.setState(DialogState._CONFIRMED);
  285. }
  286. lastResponseStringified = (String) metaData.get(LAST_RESPONSE);
  287. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  288. logger.logDebug(getDialogIdToReplicate() + " : lastResponse " + lastResponseStringified);
  289. }
  290. String dialogMethod = (String) metaData.get(DIALOG_METHOD);
  291. if(dialogMethod!= null) {
  292. method = dialogMethod;
  293. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  294. logger.logDebug(getDialogIdToReplicate() + " : dialog method " + method);
  295. }
  296. }
  297. version = new AtomicLong((Long)metaData.get(VERSION));
  298. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  299. logger.logDebug(getDialogIdToReplicate() + " : version " + version);
  300. }
  301. final Boolean isB2BUA = (Boolean) metaData.get(B2BUA);
  302. if(isB2BUA != null && isB2BUA == Boolean.TRUE) {
  303. setBackToBackUserAgent();
  304. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  305. logger.logDebug(getDialogIdToReplicate() + " : isB2BUA " + isB2BUA);
  306. }
  307. }
  308. final Boolean isReinvite = (Boolean) metaData.get(IS_REINVITE);
  309. if(isReinvite != null) {
  310. super.setReInviteFlag(isReinvite);
  311. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  312. logger.logDebug(getDialogIdToReplicate() + " : isReInvite " + isReinvite);
  313. }
  314. }
  315. final String eventHeaderStringified = (String) metaData.get(EVENT_HEADER);
  316. if(eventHeaderStringified != null) {
  317. try {
  318. super.setEventHeader((EventHeader)new EventParser(eventHeaderStringified).parse());
  319. } catch (ParseException e) {
  320. logger.logError("Unexpected exception while parsing a deserialized eventHeader", e);
  321. }
  322. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  323. logger.logDebug(getDialogIdToReplicate() + " : evenHeader " + eventHeaderStringified);
  324. }
  325. }
  326. final String remoteTargetCache = (String) metaData.get(REMOTE_TARGET);
  327. if(remoteTargetCache != null) {
  328. Contact contact = new Contact();
  329. try {
  330. super.remotePartyStringified = remoteTargetCache;
  331. contact.setAddress(addressFactory.createAddress(remoteTargetCache));
  332. super.setRemoteTarget(contact);
  333. } catch (ParseException e) {
  334. logger.logError("Unexpected exception while parsing a deserialized remoteTarget address", e);
  335. }
  336. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  337. logger.logDebug(getDialogIdToReplicate() + " : remoteTarget " + remoteTargetStringified);
  338. }
  339. }
  340. final Boolean terminateOnBye = (Boolean) metaData.get(TERMINATE_ON_BYE);
  341. if(terminateOnBye != null) {
  342. try {
  343. terminateOnBye(terminateOnBye);
  344. } catch (SipException e) {
  345. // exception is never thrown
  346. }
  347. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  348. logger.logDebug(getDialogIdToReplicate() + " : terminateOnBye " + terminateOnBye);
  349. }
  350. }
  351. final String[] routes = (String[]) metaData.get(ROUTE_LIST);
  352. if(routes != null) {
  353. final RouteList routeList = new RouteList();
  354. for (String route : routes) {
  355. try {
  356. routeList.add((Route)headerFactory.createRouteHeader(addressFactory.createAddress(route)));
  357. } catch (ParseException e) {
  358. logger.logError("Unexpected exception while parsing a deserialized route address", e);
  359. }
  360. }
  361. setRouteList(routeList);
  362. }
  363. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  364. logger.logDebug(getDialogIdToReplicate() + " : routes " + routes);
  365. }
  366. final Boolean isServer = (Boolean) metaData.get(IS_SERVER);
  367. if(isServer != null) {
  368. firstTransactionSeen = true;
  369. firstTransactionIsServerTransaction = isServer.booleanValue();
  370. super.setServerTransactionFlag(isServer.booleanValue());
  371. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  372. logger.logDebug(getDialogIdToReplicate() + " : isServer " + isServer.booleanValue());
  373. }
  374. }
  375. final Boolean firstTxSecure = (Boolean) metaData.get(FIRST_TX_SECURE);
  376. if(firstTxSecure != null) {
  377. firstTransactionSecure = firstTxSecure;
  378. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  379. logger.logDebug(getDialogIdToReplicate() + " : firstTxSecure " + firstTxSecure);
  380. }
  381. }
  382. final String firstTxId = (String) metaData.get(FIRST_TX_ID);
  383. if(firstTxId != null) {
  384. firstTransactionId = firstTxId;
  385. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  386. logger.logDebug(getDialogIdToReplicate() + " : firstTransactionId " + firstTransactionId);
  387. }
  388. }
  389. final String firstTxMethod = (String) metaData.get(FIRST_TX_METHOD);
  390. if(firstTxMethod != null) {
  391. firstTransactionMethod = firstTxMethod;
  392. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  393. logger.logDebug(getDialogIdToReplicate() + " : firstTransactionMethod " + firstTransactionMethod);
  394. }
  395. }
  396. if(recreation && isServer()) {
  397. isLatestTxServer = (Boolean) metaData.get(IS_LATEST_TX_SERVER);
  398. if(logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  399. logger.logDebug("HA SIP Dialog is Server ? " + isServer() + ", isLatestTxServer ? " + isLatestTxServer);
  400. }
  401. // http://code.google.com/p/mobicents/issues/detail?id=2942
  402. // From and To Uris switch places in certain conditions
  403. if(isLatestTxServer) {
  404. if(logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  405. logger.logDebug("switching parties on recreation");
  406. }
  407. Address remoteParty = getLocalParty();
  408. Address localParty = getRemoteParty();
  409. setLocalPartyInternal(localParty);
  410. setRemotePartyInternal(remoteParty);
  411. long remoteCSeq = getLocalSeqNumber();
  412. long localCSeq = getRemoteSeqNumber();
  413. localSequenceNumber = localCSeq;
  414. remoteSequenceNumber = remoteCSeq;
  415. }
  416. }
  417. String remoteTag = (String) metaData.get(REMOTE_TAG);
  418. setRemoteTagInternal(remoteTag);
  419. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  420. logger.logDebug(getDialogIdToReplicate() + " : remoteTag " + getRemoteTag());
  421. }
  422. String localTag = (String) metaData.get(LOCAL_TAG);
  423. setLocalTagInternal(localTag);
  424. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  425. logger.logDebug(getDialogIdToReplicate() + " : localTag " + getLocalTag());
  426. }
  427. Long remoteCSeq = (Long) metaData.get(REMOTE_CSEQ);
  428. if(remoteCSeq != null) {
  429. long cseq = remoteCSeq.longValue();
  430. if(getRemoteSeqNumber()>cseq) {
  431. if (logger.isLoggingEnabled(StackLogger.TRACE_INFO)) {
  432. logger.logInfo("Concurrency problem. Nodes are out" +
  433. " of sync. We will assume the local CSeq is the valid one. Enable request affinity to avoid this problem, remoteSequenceNumber=" +
  434. getRemoteSeqNumber() + " while other node's remote CSeq" +
  435. " number=" + cseq);
  436. }
  437. // No need to update the number, it is greater, http://code.google.com/p/mobicents/issues/detail?id=2051
  438. } else {
  439. setRemoteSequenceNumber(cseq);
  440. }
  441. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  442. logger.logDebug(getDialogIdToReplicate() + " : remoteCSeq " + getRemoteSeqNumber());
  443. }
  444. }
  445. Long localCSeq = (Long) metaData.get(LOCAL_CSEQ);
  446. if(localCSeq != null) {
  447. long cseq = localCSeq.longValue();
  448. if(localSequenceNumber>cseq) {
  449. if (logger.isLoggingEnabled(StackLogger.TRACE_INFO)) {
  450. logger.logInfo("Concurrency problem. Nodes are out" +
  451. " of sync. We will assume the local CSeq is the valid one. Enable request affinity to avoid this problem, localSequenceNumber="
  452. + localSequenceNumber+ " while other node's local CSeq" +
  453. " number=" + cseq);
  454. }
  455. // No need to update the number, it is greater, http://code.google.com/p/mobicents/issues/detail?id=2051
  456. } else {
  457. localSequenceNumber = cseq;
  458. }
  459. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  460. logger.logDebug(getDialogIdToReplicate() + " : localCSeq " + getLocalSeqNumber());
  461. }
  462. }
  463. final Boolean enableCSeqValidation = (Boolean) metaData.get(ENABLE_CSEQ_VALIDATION);
  464. if(enableCSeqValidation != null) {
  465. if(!enableCSeqValidation) disableSequenceNumberValidation();
  466. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  467. logger.logDebug(getDialogIdToReplicate() + " : CSeq validation is " + enableCSeqValidation);
  468. }
  469. }
  470. }
  471. public void setApplicationDataToReplicate(Object appData) {
  472. // the call to super is very important otherwise it triggers replication on dialog recreation
  473. super.setApplicationData(appData);
  474. }
  475. // not needed anymore the setLastResponse on final response will take care of it automatically
  476. // @Override
  477. // public void setState(int state) {
  478. // DialogState oldState = getState();
  479. // long previousVersion = -1;
  480. // if(version != null) {
  481. // previousVersion= version.get();
  482. // }
  483. // super.setState(state);
  484. // DialogState newState = getState();
  485. // // we replicate only if the state has really changed
  486. // // the fact of setting the last response upon recreation will trigger setState to be called and so the replication
  487. // // so we make sure to replicate only if the dialog has been created
  488. // // also we replicate only if the version is the same, otherwise it means setState already triggered a replication by putting the dialog in the stack and therefore in the cache
  489. // if(!newState.equals(oldState) & newState == DialogState.CONFIRMED && previousVersion != -1 && previousVersion == version.get()){
  490. // replicateState();
  491. // }
  492. // }
  493. protected abstract void replicateState();
  494. public void setLocalTagInternal(String localTag) {
  495. super.myTag = localTag;
  496. }
  497. public void setRemoteTagInternal(String remoteTag) {
  498. super.hisTag = remoteTag;
  499. }
  500. public void setLocalPartyInternal(Address localParty) {
  501. super.localParty = localParty;
  502. }
  503. public void setRemotePartyInternal(Address remoteParty) {
  504. super.remoteParty = remoteParty;
  505. }
  506. public void setContactHeader(ContactHeader contactHeader) {
  507. this.contactHeader = (Contact) contactHeader;
  508. }
  509. @Override
  510. public void setLastResponse(SIPTransaction transaction,
  511. SIPResponse sipResponse) {
  512. // version can be null on dialog recreation
  513. if(version != null) {
  514. boolean lastResponseChanged = false;
  515. long previousVersion = version.get();
  516. // for 2xx w/o 1xx
  517. final ReplicationStrategy replicationStrategy = ((ClusteredSipStack)getStack()).getReplicationStrategy();
  518. // set to confirmed dialog strategy at least
  519. int lowerStatusCodeToReplicateOn = 200;
  520. if(replicationStrategy == ReplicationStrategy.EarlyDialog) {
  521. lowerStatusCodeToReplicateOn = 101;
  522. }
  523. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  524. logger.logDebug(dialogId + " lowerStatusCodeToReplicateOn = " + lowerStatusCodeToReplicateOn);
  525. logger.logDebug(dialogId + " lastResponseStr = " + lastResponseStringified);
  526. logger.logDebug(dialogId + " sipResponse = " + sipResponse);
  527. }
  528. if(sipResponse != null && getLastResponseStringified() == null && sipResponse.getStatusCode() >= lowerStatusCodeToReplicateOn) {
  529. lastResponseChanged = true;
  530. }
  531. String responseStringified = sipResponse.toString();
  532. if(sipResponse != null && getLastResponseStringified() != null && sipResponse.getStatusCode() >= lowerStatusCodeToReplicateOn && !responseStringified.equals(this.getLastResponseStringified())) {
  533. lastResponseChanged = true;
  534. }
  535. super.setLastResponse(transaction, sipResponse);
  536. lastResponseStringified = responseStringified;
  537. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  538. logger.logDebug(dialogId + " lastResponseChanged = " + lastResponseChanged);
  539. logger.logDebug(dialogId + " previousVersion = " + previousVersion);
  540. logger.logDebug(dialogId + " currentVersion = " + version.get());
  541. }
  542. // we replicate only if the version is the same, otherwise it means lastResponse already triggered a replication by putting the dialog in the stack and therefore in the cache
  543. if(lastResponseChanged && previousVersion == version.get()) {
  544. // don't consider it a retrans even if it is on the new node taking over
  545. if(replicationStrategy == ReplicationStrategy.EarlyDialog) {
  546. sipResponse.setRetransmission(false);
  547. }
  548. replicateState();
  549. }
  550. }
  551. // causes REINVITE after NOTIFY on failover to fail with NPE since method attribute is not yet initialized
  552. // else {
  553. // super.setLastResponse(transaction, sipResponse);
  554. // }
  555. }
  556. public void setLastResponse(SIPResponse lastResponse) {
  557. // the call to super is very important otherwise it triggers replication on dialog recreation
  558. super.setLastResponse(null, lastResponse);
  559. }
  560. /**
  561. * @return the isRemoteTagSet
  562. */
  563. public boolean isRemoteTagSet() {
  564. return hisTag != null && hisTag.trim().length() > 0 ? true : false;
  565. }
  566. /**
  567. * @return the isRemoteTagSet
  568. */
  569. public boolean isLocalTagSet() {
  570. return myTag != null && myTag.trim().length() > 0 ? true : false;
  571. }
  572. /**
  573. * @return the version
  574. */
  575. public long getVersion() {
  576. return version.get();
  577. }
  578. public String getDialogIdToReplicate() {
  579. return getDialogId();
  580. // No need for this anymore since we replicate only when the last response is a final one
  581. // String cid = this.getCallId().getCallId();
  582. // StringBuilder retval = new StringBuilder(cid);
  583. // retval.append(Separators.COLON);
  584. // retval.append(myTag);
  585. // retval.append(Separators.COLON);
  586. // retval.append(hisTag);
  587. // return retval.toString().toLowerCase();
  588. }
  589. public String getLastResponseStringified() {
  590. return lastResponseStringified;
  591. }
  592. @Override
  593. public void setReInviteFlag(boolean reInviteFlag) {
  594. boolean oldReinvite = isReInvite();
  595. super.setReInviteFlag(reInviteFlag);
  596. if(reInviteFlag != oldReinvite) {
  597. isReinviteChanged = true;
  598. }
  599. }
  600. @Override
  601. protected void storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction) {
  602. super.storeFirstTransactionInfo(dialog, transaction);
  603. storeFirstTxChanged = true;
  604. }
  605. // http://code.google.com/p/mobicents/issues/detail?id=2942
  606. // From and To Uris switch places in certain conditions
  607. @Override
  608. public boolean addTransaction(SIPTransaction transaction) {
  609. if(transaction instanceof ServerTransaction) {
  610. isLatestTxServer = true;
  611. } else {
  612. isLatestTxServer = false;
  613. }
  614. return super.addTransaction(transaction);
  615. }
  616. @Override
  617. public void setRemoteTarget(ContactHeader contact) {
  618. super.setRemoteTarget(contact);
  619. remoteTargetChanged = true;
  620. }
  621. @Override
  622. public void setState(int state) {
  623. DialogState oldState = this.getState();
  624. super.setState(state);
  625. final ReplicationStrategy replicationStrategy = ((ClusteredSipStack)getStack()).getReplicationStrategy();
  626. if(replicationStrategy == ReplicationStrategy.EarlyDialog && (oldState == null || oldState.getValue() != state && state != DialogState.TERMINATED.getValue())) {
  627. dialogStateChanged = true;
  628. if (logger.isLoggingEnabled(StackLogger.TRACE_DEBUG)) {
  629. logger.logDebug("dialogStateChanged");
  630. }
  631. }
  632. }
  633. }