aClass) {
+ if (aClass == IRouter.class) {
+ return aClass.cast(this);
+ }
+ else {
+ return null;
+ }
+ }
}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/WeightedRoundRobinRouter.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/WeightedRoundRobinRouter.java
index b52a898a0..179945f4e 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/WeightedRoundRobinRouter.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/WeightedRoundRobinRouter.java
@@ -32,8 +32,8 @@
/**
* Weighted round-robin router implementation
*
- * @see http://kb.linuxvirtualserver.org/wiki/Weighted_Round-Robin_Scheduling
* @author Nils Sowen
+ * @see http://kb.linuxvirtualserver.org/wiki/Weighted_Round-Robin_Scheduling
*/
public class WeightedRoundRobinRouter extends RouterImpl {
@@ -52,7 +52,7 @@ public WeightedRoundRobinRouter(IContainer container, IConcurrentFactory concurr
/**
* Select peer by weighted round-robin scheduling
* As documented in http://kb.linuxvirtualserver.org/wiki/Weighted_Round-Robin_Scheduling
- *
+ *
*
* The weighted round-robin scheduling is designed to better handle servers
* with different processing capacities. Each server can be assigned a weight,
@@ -106,7 +106,7 @@ public WeightedRoundRobinRouter(IContainer container, IConcurrentFactory concurr
*
* This method is internally synchronized due to concurrent modifications to lastSelectedPeer and currentWeight.
* Please consider this when relying on heavy throughput.
- *
+ *
* Please note: if the list of availablePeers changes between calls (e.g. if a peer becomes active or inactive),
* the balancing algorithm is disturbed and might be distributed uneven.
* This is likely to happen if peers are flapping.
@@ -169,4 +169,24 @@ public IPeer selectPeer(List availablePeers) {
protected int gcd(int a, int b) {
return (b == 0) ? a : gcd(b, a % b);
}
+
+ /**
+ * Resets all round-robin counters/variables in order to make the whole algorithm
+ * start from scratch.
+ */
+ protected synchronized void resetRoundRobinContext() {
+ lastSelectedPeer = -1;
+ currentWeight = 0;
+ }
+
+ /**
+ * Gets a readable format of the current round-robin context, i.e. last selected
+ * peer and current weight
+ *
+ * @return readable summary of round-robin context
+ */
+ @Override
+ protected String dumpRoundRobinContext() {
+ return String.format("Current round-robin context is: lastSelectedPeer=[%d] currentWeight=[%d]", lastSelectedPeer, currentWeight);
+ }
}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/tcp/TCPClientConnection.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/tcp/TCPClientConnection.java
index 10521c373..8e6a98331 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/tcp/TCPClientConnection.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/tcp/TCPClientConnection.java
@@ -387,6 +387,15 @@ protected boolean processBufferedMessages(Event event) throws AvpDataException {
}
}
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("TCPClientConnection [createdTime=").append(createdTime)
+ .append(", cachedKey=").append(cachedKey).append(", isConnected=")
+ .append(isConnected()).append("]");
+ return builder.toString();
+ }
+
//------------------ helper classes ------------------------
private enum EventType {
CONNECTED, DISCONNECTED, MESSAGE_RECEIVED, DATA_EXCEPTION
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IClientRoSessionContext.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IClientRoSessionContext.java
index 98bc3d523..dedde8421 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IClientRoSessionContext.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IClientRoSessionContext.java
@@ -51,6 +51,7 @@
*
* @author Bartosz Baranowski
* @author Alexandre Mendonca
+ * @author Grzegorz Figiel (ProIDS sp. z o.o.)
*/
public interface IClientRoSessionContext {
@@ -62,6 +63,8 @@ public interface IClientRoSessionContext {
int getDefaultDDFHValue();
+ int getDefaultCCSFValue();
+
void grantAccessOnDeliverFailure(ClientRoSession clientCCASessionImpl, Message request);
void denyAccessOnDeliverFailure(ClientRoSession clientCCASessionImpl, Message request);
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IRoMessageFactory.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IRoMessageFactory.java
index e6bd8cecf..10569c41f 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IRoMessageFactory.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/app/ro/IRoMessageFactory.java
@@ -57,6 +57,16 @@
*/
public interface IRoMessageFactory {
+ /**
+ * Default CC-Session-Failover AVP value - NOT_SUPPORTED(0) according to RFC 4006.
+ */
+ int SESSION_FAILOVER_NOT_SUPPORTED_VALUE = 0;
+
+ /**
+ * CC-Session-Failover AVP value - SUPPORTED(1) according to RFC 4006.
+ */
+ int SESSION_FAILOVER_SUPPORTED_VALUE = 1;
+
ReAuthRequest createReAuthRequest(Request request);
ReAuthAnswer createReAuthAnswer(Answer answer);
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/data/IRoutingAwareSessionDatasource.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/data/IRoutingAwareSessionDatasource.java
new file mode 100644
index 000000000..cef1d2632
--- /dev/null
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/api/data/IRoutingAwareSessionDatasource.java
@@ -0,0 +1,68 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2016, TeleStax Inc. and individual contributors
+ * by the @authors tag.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+
+package org.jdiameter.common.api.data;
+
+import org.jdiameter.api.SessionPersistenceStorage;
+import org.jdiameter.client.api.controller.IPeer;
+
+import java.util.List;
+
+/**
+ * Extends basic session storage with capabilities of CRUD operations
+ * for session persistence records which bind sessions with peers that
+ * are processing those sessions.
+ */
+public interface IRoutingAwareSessionDatasource extends ISessionDatasource, SessionPersistenceStorage {
+
+ /**
+ * Gets a name of the peer that is currently assigned to a given session.
+ *
+ * @param sessionId session identifier used as mapping key in session storage
+ * @return peer name
+ */
+ String getSessionPeer(String sessionId);
+
+ /**
+ * Binds a particular session with a given peer.
+ *
+ * @param sessionId session identifier used as mapping key in session storage
+ * @param peer object to bind
+ */
+ void setSessionPeer(String sessionId, IPeer peer);
+
+ /**
+ * Unbinds a particular session from a given peer.
+ *
+ * @param sessionId session identifier used as mapping key in session storage
+ * @return peer name that has just been unbound
+ */
+ String removeSessionPeer(String sessionId);
+
+ /**
+ * @param sessionId session identifier used as mapping key in session storage
+ */
+ void clearUnanswerablePeers(String sessionId);
+
+ /**
+ * @param sessionId session identifier used as mapping key in session storage
+ * @return list of peers that did not answer for request within Tx timer value period
+ */
+ List getUnanswerablePeers(String sessionId);
+}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java
new file mode 100644
index 000000000..c4d74ffb2
--- /dev/null
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java
@@ -0,0 +1,125 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2016, TeleStax Inc. and individual contributors
+ * by the @authors tag.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+
+package org.jdiameter.common.impl.app;
+
+import org.jdiameter.api.app.AppEvent;
+import org.jdiameter.client.api.IMessage;
+import org.jdiameter.client.api.ISessionFactory;
+import org.jdiameter.client.api.controller.IPeer;
+import org.jdiameter.client.api.controller.IPeerTable;
+import org.jdiameter.common.api.app.IAppSessionData;
+import org.jdiameter.common.api.data.IRoutingAwareSessionDatasource;
+import org.jdiameter.common.api.data.ISessionDatasource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Routing aware extension of {@link AppSessionImpl} that enables proper diameter session
+ * load balancing. It provides diameter session persistence which maps a single diameter
+ * session to a single peer which is processing the session.
+ */
+public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl {
+
+ private static final Logger logger = LoggerFactory.getLogger(AppRoutingAwareSessionImpl.class);
+
+ private transient IPeerTable peerTable = null;
+ private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null;
+
+ /**
+ * Parameterized constructor. If session persistence is supposed to be enabled, sessionStorage
+ * argument should be of type {@link org.jdiameter.common.impl.data.RoutingAwareDataSource}.
+ *
+ * @param sessionStorage session datasource
+ * @param sessionFactory session factory
+ * @param appSessionData session data
+ */
+ public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) {
+ super(sessionFactory, appSessionData);
+ peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class);
+ if (sessionStorage instanceof IRoutingAwareSessionDatasource) {
+ sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage;
+ }
+ }
+
+ /**
+ * Initiates session persistence record, i.e. assigns the current session to a peer which is
+ * processing it. Session persistence record shall be created after a peer had answered the
+ * first (initial) request for that session.
+ *
+ * @param reqEvent request that had been sent beforehand
+ * @param ansEvent response that has been just received
+ */
+ protected void initSessionPersistenceContext(AppEvent reqEvent, AppEvent ansEvent) {
+ try {
+ IPeer peer = null;
+ if (reqEvent.getMessage() instanceof IMessage) {
+ sessionPersistenceStorage.clearUnanswerablePeers(this.getSessionId());
+ peer = ((IMessage) reqEvent.getMessage()).getPeer();
+ }
+ else {
+ logger.warn("Cannot retrieve message detailed context for Session-Id/activityId [{}]", this.getSessionId());
+ }
+
+ if (peer == null) {
+ logger.warn("Taking peer from Origin-Host AVP as no peer is assigned yet to the following message in session [{}]: [{}]", this.getSessionId(),
+ reqEvent.getMessage().getAvps());
+ peer = peerTable.getPeer(ansEvent.getOriginHost());
+ }
+
+ sessionPersistenceStorage.setSessionPeer(this.getSessionId(), peer);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Session persistent routing will be enforced for Session-Id [{}] with peer [{}]", this.getSessionId(), peer);
+ }
+
+ } catch (Exception ex) {
+ logger.error("Cannot update session persistence data, default routing will be applied", ex);
+ }
+ }
+
+ /**
+ * Removes mapping between current session and the peer that has been assigned so far.
+ *
+ * @return peer name that has been assigned so far
+ */
+ protected String flushSessionPersistenceContext() {
+ try {
+ return sessionPersistenceStorage.removeSessionPeer(this.getSessionId());
+ } catch (Exception ex) {
+ logger.error("Cannot update session persistence data", ex);
+ return null;
+ }
+ }
+
+ /**
+ * Handles expiry of session inactivity timer. Should be called by any subclasses which define
+ * any additional timers.
+ *
+ * @see org.jdiameter.common.impl.app.AppSessionImpl#onTimer(java.lang.String)
+ */
+ @Override
+ public void onTimer(String timerName) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ //no need to interfere with session state machine (simply remove routing context used for sticky sessions based routing)
+ String oldPeer = flushSessionPersistenceContext();
+ logger.debug("Idle session (inactivity) timer expired so routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId());
+ }
+ }
+}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppSessionImpl.java
index 6b094258a..69151514a 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppSessionImpl.java
@@ -42,6 +42,8 @@
package org.jdiameter.common.impl.app;
+import static org.jdiameter.client.impl.helpers.Parameters.SessionTimeOut;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -80,6 +82,8 @@ public abstract class AppSessionImpl implements AppSession {
protected ITimerFacility timerFacility;
+ protected long maxIdleTime = 0;
+
public AppSessionImpl(ISessionFactory sf, IAppSessionData appSessionData) {
if (sf == null) {
throw new IllegalArgumentException("SessionFactory must not be null");
@@ -94,6 +98,7 @@ public AppSessionImpl(ISessionFactory sf, IAppSessionData appSessionData) {
this.scheduler = assembler.getComponentInstance(IConcurrentFactory.class).
getScheduledExecutorService(IConcurrentFactory.ScheduledExecServices.ApplicationSession.name());
this.timerFacility = assembler.getComponentInstance(ITimerFacility.class);
+ this.maxIdleTime = this.sf.getContainer().getConfiguration().getLongValue(SessionTimeOut.ordinal(), (Long) SessionTimeOut.defValue());
this.session = this.sf.getNewSession(this.appSessionData.getSessionId());
//annoying ;[
ArrayList list = new ArrayList();
@@ -202,4 +207,12 @@ public boolean equals(Object obj) {
public abstract void onTimer(String timerName);
+ protected void checkIdleAppSession() {
+ if (!isValid() || (maxIdleTime > 0 && System.currentTimeMillis() - getLastAccessedTime() >= maxIdleTime)) {
+ logger.debug("Terminating idle/invalid application session [{}] with SID[{}]", this, getSessionId());
+ release();
+ }
+ }
+
+
}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/AppCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/AppCCASessionImpl.java
index 83919a918..d7a0e1123 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/AppCCASessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/AppCCASessionImpl.java
@@ -52,14 +52,15 @@
import org.jdiameter.api.cca.CCASession;
import org.jdiameter.client.api.ISessionFactory;
import org.jdiameter.common.api.app.IAppSessionData;
-import org.jdiameter.common.impl.app.AppSessionImpl;
+import org.jdiameter.common.api.data.ISessionDatasource;
+import org.jdiameter.common.impl.app.AppRoutingAwareSessionImpl;
/**
*
* @author Bartosz Baranowski
* @author Alexandre Mendonca
*/
-public abstract class AppCCASessionImpl extends AppSessionImpl implements CCASession, NetworkReqListener {
+public abstract class AppCCASessionImpl extends AppRoutingAwareSessionImpl implements CCASession,NetworkReqListener {
protected Lock sendAndStateLock = new ReentrantLock();
@@ -68,8 +69,8 @@ public abstract class AppCCASessionImpl extends AppSessionImpl implements CCASes
//FIXME: use FastList ?
protected List stateListeners = new CopyOnWriteArrayList();
- public AppCCASessionImpl(ISessionFactory sf, IAppSessionData data) {
- super(sf, data);
+ public AppCCASessionImpl(ISessionDatasource sessionStorage, ISessionFactory sf, IAppSessionData data) {
+ super(sessionStorage, sf, data);
}
@Override
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/CCASessionFactoryImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/CCASessionFactoryImpl.java
index d8bf0d2f7..1124f91fb 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/CCASessionFactoryImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/cca/CCASessionFactoryImpl.java
@@ -94,7 +94,7 @@ public CCASessionFactoryImpl(SessionFactory sessionFactory) {
}
/**
- * @param sessionFactory2
+ * @param sessionFactory
*/
public void init(SessionFactory sessionFactory) {
this.sessionFactory = (ISessionFactory) sessionFactory;
@@ -278,8 +278,14 @@ public AppSession getSession(String sessionId, Class extends AppSession> aClas
ClientCCASessionImpl clientSession = null;
IClientCCASessionData data = (IClientCCASessionData) this.sessionDataFactory.getAppSessionData(ClientCCASession.class, sessionId);
- clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), sessionFactory, this.getClientSessionListener(),
- this.getClientContextListener(), this.getStateListener());
+ if (!sessionFactory.isSessionPersistenceEnabled()) {
+ clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), sessionFactory,
+ this.getClientSessionListener(), this.getClientContextListener(), this.getStateListener());
+ }
+ else {
+ clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), iss, sessionFactory,
+ this.getClientSessionListener(), this.getClientContextListener(), this.getStateListener());
+ }
clientSession.getSessions().get(0).setRequestListener(clientSession);
appSession = clientSession;
}
@@ -320,8 +326,14 @@ public AppSession getNewSession(String sessionId, Class extends AppSession> aC
}
IClientCCASessionData data = (IClientCCASessionData) this.sessionDataFactory.getAppSessionData(ClientCCASession.class, sessionId);
data.setApplicationId(applicationId);
- clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), sessionFactory, this.getClientSessionListener(),
- this.getClientContextListener(), this.getStateListener());
+ if (!sessionFactory.isSessionPersistenceEnabled()) {
+ clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), sessionFactory,
+ this.getClientSessionListener(), this.getClientContextListener(), this.getStateListener());
+ }
+ else {
+ clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), iss, sessionFactory,
+ this.getClientSessionListener(), this.getClientContextListener(), this.getStateListener());
+ }
// this goes first!
iss.addSession(clientSession);
clientSession.getSessions().get(0).setRequestListener(clientSession);
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/AppRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/AppRoSessionImpl.java
index cff2a7435..729c057b9 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/AppRoSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/AppRoSessionImpl.java
@@ -52,14 +52,15 @@
import org.jdiameter.api.app.StateMachine;
import org.jdiameter.client.api.ISessionFactory;
import org.jdiameter.common.api.app.ro.IRoSessionData;
-import org.jdiameter.common.impl.app.AppSessionImpl;
+import org.jdiameter.common.api.data.ISessionDatasource;
+import org.jdiameter.common.impl.app.AppRoutingAwareSessionImpl;
/**
*
* @author Bartosz Baranowski
* @author Alexandre Mendonca
*/
-public abstract class AppRoSessionImpl extends AppSessionImpl implements NetworkReqListener, StateMachine {
+public abstract class AppRoSessionImpl extends AppRoutingAwareSessionImpl implements NetworkReqListener, StateMachine {
protected Lock sendAndStateLock = new ReentrantLock();
@@ -67,8 +68,8 @@ public abstract class AppRoSessionImpl extends AppSessionImpl implements Network
//FIXME: change this to single ref!
protected transient List stateListeners = new CopyOnWriteArrayList();
- public AppRoSessionImpl(ISessionFactory sf, IRoSessionData sessionData) {
- super(sf, sessionData);
+ public AppRoSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sf, IRoSessionData sessionData) {
+ super(sessionStorage, sf, sessionData);
}
@Override
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/RoSessionFactoryImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/RoSessionFactoryImpl.java
index e139b07ff..5bacdbad0 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/RoSessionFactoryImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/RoSessionFactoryImpl.java
@@ -25,7 +25,9 @@
import org.jdiameter.api.ApplicationId;
import org.jdiameter.api.InternalException;
import org.jdiameter.api.Message;
+import org.jdiameter.api.Peer;
import org.jdiameter.api.Request;
+import org.jdiameter.api.RouteException;
import org.jdiameter.api.SessionFactory;
import org.jdiameter.api.app.AppAnswerEvent;
import org.jdiameter.api.app.AppRequestEvent;
@@ -61,6 +63,7 @@
*
* @author Alexandre Mendonca
* @author Bartosz Baranowski
+ * @author Grzegorz Figiel (ProIDS sp. z o.o.)
*/
public class RoSessionFactoryImpl implements IRoSessionFactory, ClientRoSessionListener, ServerRoSessionListener, StateChangeListener,
IRoMessageFactory, IServerRoSessionContext, IClientRoSessionContext {
@@ -68,6 +71,7 @@ public class RoSessionFactoryImpl implements IRoSessionFactory, ClientRoSessionL
// Message timeout value (in milliseconds)
protected int defaultDirectDebitingFailureHandling = 0;
protected int defaultCreditControlFailureHandling = 0;
+ protected int defaultCreditControlSessionFailover = IRoMessageFactory.SESSION_FAILOVER_NOT_SUPPORTED_VALUE;
// its seconds
protected long defaultValidityTime = 60;
@@ -270,8 +274,8 @@ public AppSession getNewSession(String sessionId, Class extends AppSession> aC
IClientRoSessionData sessionData = (IClientRoSessionData) this.sessionDataFactory.getAppSessionData(ClientRoSession.class, sessionId);
sessionData.setApplicationId(applicationId);
- clientSession = new ClientRoSessionImpl(sessionData, this.getMessageFactory(), sessionFactory, this.getClientSessionListener(),
- this.getClientContextListener(), this.getStateListener());
+ clientSession = new ClientRoSessionImpl(sessionData, this.getMessageFactory(), iss, sessionFactory, this.getClientSessionListener(), this
+ .getClientContextListener(), this.getStateListener());
// this goes first!
iss.addSession(clientSession);
clientSession.getSessions().get(0).setRequestListener(clientSession);
@@ -320,8 +324,8 @@ public AppSession getSession(String sessionId, Class extends AppSession> aClas
try {
if (aClass == ClientRoSession.class) {
IClientRoSessionData sessionData = (IClientRoSessionData) this.sessionDataFactory.getAppSessionData(ClientRoSession.class, sessionId);
- ClientRoSessionImpl clientSession = new ClientRoSessionImpl(sessionData, this.getMessageFactory(), sessionFactory, this.getClientSessionListener(),
- this.getClientContextListener(), this.getStateListener());
+ ClientRoSessionImpl clientSession = new ClientRoSessionImpl(sessionData, this.getMessageFactory(), iss, sessionFactory, this.getClientSessionListener
+ (), this.getClientContextListener(), this.getStateListener());
// this goes first!
clientSession.getSessions().get(0).setRequestListener(clientSession);
appSession = clientSession;
@@ -372,6 +376,21 @@ public void doOtherEvent(AppSession session, AppRequestEvent request, AppAnswerE
}
+ @Override
+ public void doRequestTxTimeout(ClientRoSession session, Message msg, Peer peer) throws InternalException {
+
+ }
+
+ @Override
+ public void doRequestTimeout(ClientRoSession session, Message msg, Peer peer) throws InternalException {
+
+ }
+
+ @Override
+ public void doPeerUnavailability(ClientRoSession session, Message msg, Peer peer, RouteException cause) throws InternalException {
+
+ }
+
// Message Factory Methods --------------------------------------------------
@Override
@@ -466,6 +485,11 @@ public int getDefaultCCFHValue() {
return defaultCreditControlFailureHandling;
}
+ @Override
+ public int getDefaultCCSFValue() {
+ return defaultCreditControlSessionFailover;
+ }
+
@Override
public int getDefaultDDFHValue() {
return defaultDirectDebitingFailureHandling;
@@ -498,14 +522,13 @@ public void indicateServiceError(ClientRoSession clientRoSessionImpl) {
@Override
public void txTimerExpired(ClientRoSession session) {
- // this.resourceAdaptor.sessionDestroyed(session.getSessions().get(0).getSessionId(), session);
- session.release();
+ // TODO Auto-generated method stub
}
@Override
public long[] getApplicationIds() {
// FIXME: What should we do here?
- return new long[] { 4 };
+ return new long[]{4};
}
@Override
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/LocalDataSource.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/LocalDataSource.java
index d066798e6..708194ba6 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/LocalDataSource.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/LocalDataSource.java
@@ -89,7 +89,7 @@ public class LocalDataSource implements ISessionDatasource {
protected HashMap, IAppSessionDataFactory extends IAppSessionData>> appSessionDataFactories =
new HashMap, IAppSessionDataFactory extends IAppSessionData>>();
- private ConcurrentHashMap sessionIdToEntry = new ConcurrentHashMap();
+ protected ConcurrentHashMap sessionIdToEntry = new ConcurrentHashMap();
private static final Logger logger = LoggerFactory.getLogger(LocalDataSource.class);
@@ -152,23 +152,34 @@ public NetworkReqListener removeSessionListener(String sessionId) {
@Override
public void addSession(BaseSession session) {
- logger.debug("addSession({})", session);
- SessionEntry se = null;
+ addSession(session, SessionEntry.class);
+ }
+
+ protected void addSession(BaseSession session, Class sessionWraperType) {
+ logger.debug("addSession({}) => {}", session.getSessionId(), session);
+ T se = null;
String sessionId = session.getSessionId();
//FIXME: check here replicable vs not replicable?
if (this.sessionIdToEntry.containsKey(sessionId)) {
- se = this.sessionIdToEntry.get(sessionId);
- if ( !(se.session instanceof ISession) || se.session.isReplicable()) { //must be not replicable so we can "overwrite"
- throw new IllegalArgumentException("Sessin with id: " + sessionId + ", already exists!");
- }
- else {
- this.sessionIdToEntry.put(sessionId, se);
+ se = sessionWraperType.cast(this.sessionIdToEntry.get(sessionId));
+ if( se != null && (!(se.session instanceof ISession) || se.session.isReplicable()) ) { //must be not replicable so we can "overwrite"
+ throw new IllegalArgumentException("Session with id: " + sessionId + ", already exists!");
}
}
- else {
- se = new SessionEntry();
+
+ if(se == null) {
+ try {
+ se = sessionWraperType.newInstance();
+ } catch (InstantiationException e) {
+ logger.warn("Cannot instantiate session object of type: " + sessionWraperType.getCanonicalName(), e);
+ throw new IllegalArgumentException("Cannot instantiate session object of type: " + sessionWraperType.getCanonicalName(), e);
+ } catch (IllegalAccessException e) {
+ logger.warn("Cannot instantiate session object of type: " + sessionWraperType.getCanonicalName(), e);
+ throw new IllegalArgumentException("Cannot instantiate session object of type: " + sessionWraperType.getCanonicalName(), e);
+ }
}
+
se.session = session;
this.sessionIdToEntry.put(session.getSessionId(), se);
}
@@ -217,7 +228,7 @@ public String toString() {
}
//simple class to reduce collections overhead.
- private class SessionEntry {
+ protected static class SessionEntry {
BaseSession session;
NetworkReqListener listener;
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/RoutingAwareDataSource.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/RoutingAwareDataSource.java
new file mode 100644
index 000000000..f7b424f28
--- /dev/null
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/RoutingAwareDataSource.java
@@ -0,0 +1,203 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2016, TeleStax Inc. and individual contributors
+ * by the @authors tag.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+
+package org.jdiameter.common.impl.data;
+
+import org.jdiameter.api.BaseSession;
+import org.jdiameter.client.api.IContainer;
+import org.jdiameter.client.api.controller.IPeer;
+import org.jdiameter.common.api.data.IRoutingAwareSessionDatasource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation of routing aware session datasource for {@link IRoutingAwareSessionDatasource}.
+ */
+public class RoutingAwareDataSource extends LocalDataSource implements IRoutingAwareSessionDatasource {
+
+ private static final Logger logger = LoggerFactory.getLogger(RoutingAwareDataSource.class);
+
+
+ /**
+ * Default constructor.
+ */
+ public RoutingAwareDataSource() {
+ super();
+ logger.debug("Constructor for RoutingAwareDataSource: nothing to do");
+ }
+
+ /**
+ * Parameterized constructor. Should be called by any subclasses.
+ *
+ * @param container container object
+ */
+ public RoutingAwareDataSource(IContainer container) {
+ super(container);
+ logger.debug("Constructor for RoutingAwareDataSource: nothing to do");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.jdiameter.common.impl.data.LocalDataSource#addSession(org.jdiameter.api.BaseSession)
+ */
+ @Override
+ public void addSession(BaseSession session) {
+ addSession(session, RoutingAwareSessionEntry.class);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.jdiameter.common.api.data.IRoutingAwareSessionDatasource#setSessionPeer(java.lang.String, org.jdiameter.client.api.controller.IPeer)
+ */
+ @Override
+ public void setSessionPeer(String sessionId, IPeer peer) {
+ logger.debug("Assigning routing destination peer [{}] to session [{}]", peer, sessionId);
+ SessionEntry se = sessionIdToEntry.get(sessionId);
+ if (se == null) {
+ throw new IllegalArgumentException("No session entry for id: " + sessionId);
+ }
+ else if (!(se instanceof RoutingAwareSessionEntry)) {
+ throw new IllegalArgumentException("Session entry is of a wrong type for id: " + sessionId);
+ }
+ else {
+ ((RoutingAwareSessionEntry) se).peer = peer.getUri().getFQDN();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.jdiameter.common.api.data.IRoutingAwareSessionDatasource#getSessionPeer(java.lang.String)
+ */
+ @Override
+ public String getSessionPeer(String sessionId) {
+ SessionEntry se = sessionIdToEntry.get(sessionId);
+ logger.debug("Looking up routing peer for session [{}]: {}", sessionId, se);
+ return (se != null && se instanceof RoutingAwareSessionEntry) ? ((RoutingAwareSessionEntry) se).peer : null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.jdiameter.common.api.data.IRoutingAwareSessionDatasource#removeSessionPeer(java.lang.String)
+ */
+ @Override
+ public String removeSessionPeer(String sessionId) {
+ SessionEntry se = sessionIdToEntry.get(sessionId);
+ logger.debug("Looking up routing peer for removal for session [{}]: {}", sessionId, se);
+ if (se != null && se instanceof RoutingAwareSessionEntry) {
+ String oldPeer = ((RoutingAwareSessionEntry) se).peer;
+ ((RoutingAwareSessionEntry) se).peer = null;
+ ((RoutingAwareSessionEntry) se).getUnanswerablePeers().add(oldPeer);
+ return oldPeer;
+ }
+ else {
+ return null;
+ }
+ }
+
+ @Override
+ public void clearUnanswerablePeers(String sessionId) {
+ SessionEntry se = sessionIdToEntry.get(sessionId);
+ if (se != null && se instanceof RoutingAwareSessionEntry) {
+ ((RoutingAwareSessionEntry) se).getUnanswerablePeers().clear();
+ }
+ }
+
+ @Override
+ public List getUnanswerablePeers(String sessionId) {
+ SessionEntry se = sessionIdToEntry.get(sessionId);
+ if (se != null && se instanceof RoutingAwareSessionEntry) {
+ return ((RoutingAwareSessionEntry) se).getUnanswerablePeers();
+ }
+ else {
+ return null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.jdiameter.api.SessionPersistenceStorage#dumpStickySessions(int)
+ */
+ @Override
+ public List dumpStickySessions(int maxLimit) {
+ int counter = 0;
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ List sessions = maxLimit > 0 ? new ArrayList(maxLimit) : new ArrayList(sessionIdToEntry.size());
+
+ logger.debug("Reading [{}] sessions out of [{}]", maxLimit > 0 ? String.valueOf(maxLimit) : "unlimited", sessionIdToEntry.size());
+
+ for (Map.Entry entry : sessionIdToEntry.entrySet()) {
+ if (entry.getValue() instanceof RoutingAwareSessionEntry) {
+ RoutingAwareSessionEntry tmpEntry = (RoutingAwareSessionEntry) entry.getValue();
+ if (tmpEntry.peer != null) {
+ sessions.add(tmpEntry.preetyPrint(entry.getKey(), dateFormat));
+ if (maxLimit > 0 && ++counter >= maxLimit) {
+ break;
+ }
+ }
+ }
+ }
+
+ return sessions;
+ }
+
+ /**
+ * Extends basic session entry, which is used to store records in session storage, with extra info about
+ * a specific peer that is bound to a particular session. Extra info is used for session persistent routing.
+ */
+ protected static class RoutingAwareSessionEntry extends SessionEntry {
+ private List unanswerable = new ArrayList();
+ String peer;
+
+ public List getUnanswerablePeers() {
+ return unanswerable;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("RoutingAwareSessionEntry [peer=").append(peer).append(", unanswerable=[").append(Arrays.toString(unanswerable.toArray())).append("], " +
+ "toString()=").append(super.toString()).append("]");
+ return builder.toString();
+ }
+
+ /**
+ * Gets a readable and more user friendly format of an entry.
+ *
+ * @param key key used to store that entry in a session storage map
+ * @param dateFormat format used to print last session activity timestamp
+ * @return readable representation of this session entry
+ */
+ public String preetyPrint(String key, DateFormat dateFormat) {
+ StringBuilder builder = new StringBuilder("{id=[");
+ builder.append(key).append("], peer=[").append(peer)
+ .append("], timestamp=[").append(dateFormat.format(new Date(session.getLastAccessedTime())))
+ .append("], unanswerable=[").append(Arrays.toString(unanswerable.toArray()))
+ .append("]}").toString();
+ return builder.toString();
+ }
+ }
+}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/timer/LocalTimerFacilityImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/timer/LocalTimerFacilityImpl.java
index c2c2b2302..f08b3c700 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/timer/LocalTimerFacilityImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/timer/LocalTimerFacilityImpl.java
@@ -55,6 +55,7 @@
import org.apache.commons.pool.impl.GenericObjectPool;
import org.jdiameter.api.BaseSession;
import org.jdiameter.client.api.IContainer;
+import org.jdiameter.client.impl.BaseSessionImpl;
import org.jdiameter.common.api.concurrent.IConcurrentFactory;
import org.jdiameter.common.api.data.ISessionDatasource;
import org.jdiameter.common.api.timer.ITimerFacility;
@@ -96,6 +97,7 @@ public void cancel(Serializable f) {
if (f != null && f instanceof TimerTaskHandle) {
TimerTaskHandle timerTaskHandle = (TimerTaskHandle) f;
if (timerTaskHandle.future != null) {
+ logger.debug("Cancelling timer with id [{}] and delay [{}]", timerTaskHandle.id, timerTaskHandle.future.getDelay(TimeUnit.MILLISECONDS));
if (executor.remove((Runnable) timerTaskHandle.future)) {
timerTaskHandle.future.cancel(false);
returnTimerTaskHandle(timerTaskHandle);
@@ -167,18 +169,24 @@ private final class TimerTaskHandle implements Runnable, Externalizable {
public void run() {
try {
BaseSession bSession = sessionDataSource.getSession(sessionId);
- if (bSession == null || !bSession.isAppSession()) {
+ if (bSession == null) {
// FIXME: error ?
logger.error("Base Session is null for sessionId: {}", sessionId);
return;
}
else {
try {
- AppSessionImpl impl = (AppSessionImpl) bSession;
- impl.onTimer(timerName);
+ if (!bSession.isAppSession()) {
+ BaseSessionImpl impl = (BaseSessionImpl) bSession;
+ impl.onTimer(timerName);
+ }
+ else {
+ AppSessionImpl impl = (AppSessionImpl) bSession;
+ impl.onTimer(timerName);
+ }
}
catch (Exception e) {
- logger.error("Caught exception from app session object!", e);
+ logger.error("Caught exception from session object!", e);
}
}
}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/FailureAwareRouter.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/FailureAwareRouter.java
new file mode 100644
index 000000000..11b87a8d1
--- /dev/null
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/FailureAwareRouter.java
@@ -0,0 +1,41 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2016, TeleStax Inc. and individual contributors
+ * by the @authors tag.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+
+package org.jdiameter.server.impl;
+
+import org.jdiameter.api.Configuration;
+import org.jdiameter.api.MetaData;
+import org.jdiameter.client.api.IContainer;
+import org.jdiameter.client.api.controller.IRealmTable;
+import org.jdiameter.common.api.concurrent.IConcurrentFactory;
+import org.jdiameter.server.api.IRouter;
+
+/**
+ * Just a simple counterpart of failure aware router defined for a client role.
+ */
+public class FailureAwareRouter extends org.jdiameter.client.impl.router.FailureAwareRouter implements IRouter {
+
+ /**
+ * Parameterized constructor. Should be called by any subclasses.
+ */
+ public FailureAwareRouter(IContainer container, IConcurrentFactory concurrentFactory, IRealmTable realmTable, Configuration config, MetaData aMetaData) {
+ super(container, concurrentFactory, realmTable, config, aMetaData);
+ }
+
+}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/MutablePeerTableImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/MutablePeerTableImpl.java
index 895f52bb9..df6ce41ac 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/MutablePeerTableImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/MutablePeerTableImpl.java
@@ -43,7 +43,6 @@
package org.jdiameter.server.impl;
import static org.jdiameter.client.impl.helpers.Parameters.PeerName;
-import static org.jdiameter.client.impl.helpers.Parameters.PeerTable;
import static org.jdiameter.client.impl.helpers.Parameters.StopTimeOut;
import static org.jdiameter.client.impl.helpers.Parameters.UseUriAsFqdn;
import static org.jdiameter.common.api.concurrent.IConcurrentFactory.ScheduledExecServices.ConnectionTimer;
@@ -100,6 +99,7 @@
import org.jdiameter.client.api.io.TransportException;
import org.jdiameter.client.api.parser.IMessageParser;
import org.jdiameter.client.impl.controller.PeerTableImpl;
+import org.jdiameter.client.impl.helpers.Parameters;
import org.jdiameter.common.api.concurrent.IConcurrentFactory;
import org.jdiameter.common.api.statistic.IStatisticManager;
import org.jdiameter.server.api.IFsmFactory;
@@ -227,6 +227,30 @@ public MutablePeerTableImpl(Configuration config, MetaData metaData, IContainer
logger.debug("MutablePeerTableImpl has finished initialisation");
}
+ protected Configuration getPeerConfig(String fqdn) throws URISyntaxException, UnknownServiceException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Searching configuration for peer fqdn: " + fqdn);
+ }
+ Configuration result = null;
+ Configuration[] peers = config.getChildren(Parameters.PeerTable.ordinal());
+ if (peers != null && peers.length > 0) {
+ for (Configuration peerConfig : peers) {
+ if (peerConfig.isAttributeExist(PeerName.ordinal())) {
+ String peerConfigFqdn = new URI(peerConfig.getStringValue(PeerName.ordinal(), "")).getFQDN();
+ if (fqdn.equals(peerConfigFqdn)) {
+ result = peerConfig;
+ break;
+ }
+ }
+ }
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Peer configuration {}found for FQDN: {}", (result == null ? "not " : ""), fqdn);
+ }
+ return result;
+ }
+
+
@Override
protected Peer createPeer(int rating, String uri, String ip, String portRange, MetaData metaData, Configuration globalConfig,
Configuration peerConfig, org.jdiameter.client.api.fsm.IFsmFactory fsmFactory,
@@ -445,7 +469,8 @@ public void messageReceived(String connKey, IMessage message) {
try {
realm = message.getAvps().getAvp(Avp.ORIGIN_REALM).getDiameterIdentity();
logger.debug("Origin-Realm in new received message is [{}]", realm);
- } catch (AvpDataException e) {
+ }
+ catch (AvpDataException e) {
logger.warn("Unable to retrieve find Origin-Realm AVP in CER", e);
unregister(true);
return;
@@ -510,7 +535,7 @@ public void messageReceived(String connKey, IMessage message) {
}
peer = newPeerInstance(0, uri, connection.getRemoteAddress().getHostAddress(), null, false, connection,
- metaData, config, null, fsmFactory, transportFactory, parser, statisticFactory, concurrentFactory);
+ metaData, config, getPeerConfig(uri.getFQDN()), fsmFactory, transportFactory, parser, statisticFactory, concurrentFactory);
logger.debug("Created new peer instance [{}] and adding to peer table", peer);
peer.setRealm(realm);
appendPeerToPeerTable(peer);
@@ -563,7 +588,7 @@ public void unregister(boolean release) {
}
}
}
- );
+ );
}
private void appendPeerToPeerTable(IPeer peer) {
@@ -639,15 +664,8 @@ public Peer addPeer(URI peerURI, String realm, boolean connecting) {
//TODO: add sKey here, now it adds peer to all realms.
//TODO: better, separate addPeer from realm!
try {
- Configuration peerConfig = null;
- Configuration[] peers = config.getChildren(PeerTable.ordinal());
- // find peer config
- for (Configuration c : peers) {
- if (peerURI.getFQDN().equals(c.getStringValue(PeerName.ordinal(), ""))) {
- peerConfig = c;
- break;
- }
- }
+ Configuration peerConfig = getPeerConfig(peerURI.getFQDN());
+
if (peerConfig == null) {
peerConfig = new EmptyConfiguration(false).add(PeerAttemptConnection, connecting);
}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/PeerImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/PeerImpl.java
index 1b8be7612..07d3422ce 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/PeerImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/PeerImpl.java
@@ -205,9 +205,10 @@ public void notifyOvrManager(IOverloadManager ovrManager) {
@Override
public String toString() {
if (fsm != null) {
- return "SPeer{" + "Uri=" + uri + "; State=" + fsm.getState(PeerState.class) + "; con=" + connection + "; incCon" + incConnections + " }";
+ return "SPeer{" + "Uri=" + uri + "; State=" + fsm.getState(PeerState.class)
+ + "; Rating=" + rating + "; con="+ connection +"; incCon="+incConnections+" }";
}
- return "SPeer{" + "Uri=" + uri + "; State=" + fsm + "; con=" + connection + "; incCon" + incConnections + " }";
+ return "SPeer{" + "Uri=" + uri + "; State=" + fsm + "; Rating=" + rating + "; con="+ connection +"; incCon="+incConnections+" }";
}
protected class LocalActionConext extends ActionContext {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/acc/ServerAccSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/acc/ServerAccSessionImpl.java
index 78a5d7bc1..278094528 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/acc/ServerAccSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/acc/ServerAccSessionImpl.java
@@ -407,7 +407,10 @@ private void cancelTsTimer() {
*/
@Override
public void onTimer(String timerName) {
- if (timerName.equals(TIMER_NAME_TS)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(TIMER_NAME_TS)) {
if (context != null) {
try {
context.sessionTimeoutElapses(ServerAccSessionImpl.this);
@@ -419,7 +422,7 @@ public void onTimer(String timerName) {
setState(IDLE);
}
else {
- // FIXME: ???
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
}
}
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/auth/ServerAuthSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/auth/ServerAuthSessionImpl.java
index 8f79a4461..030c8765f 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/auth/ServerAuthSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/auth/ServerAuthSessionImpl.java
@@ -453,7 +453,10 @@ protected void cancelTsTimer() {
*/
@Override
public void onTimer(String timerName) {
- if (timerName.equals(TIMER_NAME_TS)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(TIMER_NAME_TS)) {
try {
sendAndStateLock.lock();
sessionData.setTsTimerId(null);
@@ -466,6 +469,9 @@ public void onTimer(String timerName) {
sendAndStateLock.unlock();
}
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
@Override
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cca/ServerCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cca/ServerCCASessionImpl.java
index c3e2cf37e..c6619595d 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cca/ServerCCASessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cca/ServerCCASessionImpl.java
@@ -107,7 +107,7 @@ public class ServerCCASessionImpl extends AppCCASessionImpl implements ServerCCA
public ServerCCASessionImpl(IServerCCASessionData data, ICCAMessageFactory fct, ISessionFactory sf, ServerCCASessionListener lst,
IServerCCASessionContext ctx, StateChangeListener stLst) {
- super(sf, data);
+ super(null, sf, data);
if (lst == null) {
throw new IllegalArgumentException("Listener can not be null");
}
@@ -419,9 +419,15 @@ private void startTcc(Avp validityAvp) {
*/
@Override
public void onTimer(String timerName) {
- if (timerName.equals(TCC_TIMER_NAME)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(TCC_TIMER_NAME)) {
new TccScheduledTask(this).run();
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
private void stopTcc(boolean willRestart) {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cxdx/CxDxServerSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cxdx/CxDxServerSessionImpl.java
index d068a5141..033301563 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cxdx/CxDxServerSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cxdx/CxDxServerSessionImpl.java
@@ -395,7 +395,10 @@ protected void setState(CxDxSessionState newState) {
@Override
public void onTimer(String timerName) {
- if (timerName.equals(CxDxSession.TIMER_NAME_MSG_TIMEOUT)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(CxDxSession.TIMER_NAME_MSG_TIMEOUT)) {
try {
sendAndStateLock.lock();
try {
@@ -411,6 +414,9 @@ public void onTimer(String timerName) {
sendAndStateLock.unlock();
}
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
private class RequestDelivery implements Runnable {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gq/GqServerSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gq/GqServerSessionImpl.java
index 786d2ce9f..fc1148d8e 100755
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gq/GqServerSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gq/GqServerSessionImpl.java
@@ -479,7 +479,10 @@ protected void cancelTsTimer() {
*/
@Override
public void onTimer(String timerName) {
- if (timerName.equals(TIMER_NAME_TS)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(TIMER_NAME_TS)) {
try {
sendAndStateLock.lock();
sessionData.setTsTimerId(null);
@@ -492,6 +495,9 @@ public void onTimer(String timerName) {
sendAndStateLock.unlock();
}
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
protected ReAuthAnswer createReAuthAnswer(Answer answer) {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gx/ServerGxSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gx/ServerGxSessionImpl.java
index df57e0f93..af5bd3f98 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gx/ServerGxSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/gx/ServerGxSessionImpl.java
@@ -410,9 +410,15 @@ private void startTcc(Avp validityAvp) {
*/
@Override
public void onTimer(String timerName) {
- if (timerName.equals(TCC_TIMER_NAME)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(TCC_TIMER_NAME)) {
new TccScheduledTask(this).run();
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
private void stopTcc(boolean willRestart) {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rf/ServerRfSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rf/ServerRfSessionImpl.java
index d5b01100d..6e86e99fe 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rf/ServerRfSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rf/ServerRfSessionImpl.java
@@ -392,7 +392,10 @@ private void cancelTsTimer() {
*/
@Override
public void onTimer(String timerName) {
- if (timerName.equals(TIMER_NAME_TS)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(TIMER_NAME_TS)) {
if (context != null) {
try {
context.sessionTimeoutElapses(ServerRfSessionImpl.this);
@@ -403,6 +406,9 @@ public void onTimer(String timerName) {
}
setState(IDLE);
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
protected Answer createStopAnswer(Request request) {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/ro/ServerRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/ro/ServerRoSessionImpl.java
index 241b4a89e..ec79a5ac5 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/ro/ServerRoSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/ro/ServerRoSessionImpl.java
@@ -108,7 +108,7 @@ public class ServerRoSessionImpl extends AppRoSessionImpl implements ServerRoSes
public ServerRoSessionImpl(IServerRoSessionData sessionData, IRoMessageFactory fct, ISessionFactory sf, ServerRoSessionListener lst,
IServerRoSessionContext ctx, StateChangeListener stLst) {
- super(sf, sessionData);
+ super(null, sf, sessionData);
if (sessionData == null) {
throw new IllegalArgumentException("SessionData can not be null");
}
@@ -429,9 +429,15 @@ private void startTcc(Avp validityAvp) {
*/
@Override
public void onTimer(String timerName) {
- if (timerName.equals(TCC_TIMER_NAME)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(TCC_TIMER_NAME)) {
new TccScheduledTask(this).run();
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
private void stopTcc(boolean willRestart) {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rx/ServerRxSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rx/ServerRxSessionImpl.java
index 314f05708..9ea4133d9 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rx/ServerRxSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/rx/ServerRxSessionImpl.java
@@ -346,6 +346,12 @@ public void receivedSuccessMessage(Request request, Answer answer) {
*/
@Override
public void onTimer(String timerName) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
@Override
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s13/S13ServerSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s13/S13ServerSessionImpl.java
index 6ee368b75..93449f972 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s13/S13ServerSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s13/S13ServerSessionImpl.java
@@ -212,7 +212,10 @@ protected void setState(S13SessionState newState) {
@Override
public void onTimer(String timerName) {
- if (timerName.equals(S13Session.TIMER_NAME_MSG_TIMEOUT)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(S13Session.TIMER_NAME_MSG_TIMEOUT)) {
try {
sendAndStateLock.lock();
try {
@@ -226,6 +229,9 @@ public void onTimer(String timerName) {
sendAndStateLock.unlock();
}
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
@Override
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s6a/S6aServerSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s6a/S6aServerSessionImpl.java
index fee538f10..f531f36ee 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s6a/S6aServerSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/s6a/S6aServerSessionImpl.java
@@ -391,7 +391,10 @@ protected void setState(S6aSessionState newState) {
@Override
public void onTimer(String timerName) {
- if (timerName.equals(S6aSession.TIMER_NAME_MSG_TIMEOUT)) {
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else if (timerName.equals(S6aSession.TIMER_NAME_MSG_TIMEOUT)) {
try {
sendAndStateLock.lock();
try {
@@ -407,6 +410,9 @@ public void onTimer(String timerName) {
sendAndStateLock.unlock();
}
}
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
@Override
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/sh/ShServerSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/sh/ShServerSessionImpl.java
index ec2b55f85..0daa56690 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/sh/ShServerSessionImpl.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/sh/ShServerSessionImpl.java
@@ -341,7 +341,12 @@ else if (!sessionData.equals(other.sessionData)) {
@Override
public void onTimer(String timerName) {
- logger.trace("onTimer({})", timerName);
+ if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
+ checkIdleAppSession();
+ }
+ else {
+ logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
+ }
}
private class RequestDelivery implements Runnable {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/EmptyConfiguration.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/EmptyConfiguration.java
index 13b3d89b1..74327bd19 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/EmptyConfiguration.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/EmptyConfiguration.java
@@ -212,6 +212,22 @@ public void setByteArrayValue(int key, byte[] value) {
}
@Override
+ public void setIntArrayValue(int key, int[] value) {
+ List list = listeners.get(key);
+ if (list != null) {
+ boolean commit = true;
+ for (ConfigurationListener l : list) {
+ commit &= l.elementChanged(key, value);
+ }
+ if (commit) {
+ putValue(key, value);
+ }
+ }
+ else {
+ putValue(key, value);
+ }
+ }
+
public void setBooleanValue(int key, boolean value) {
List list = listeners.get(key);
if (list != null) {
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/XMLConfiguration.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/XMLConfiguration.java
index 0760eb62c..31d82f210 100644
--- a/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/XMLConfiguration.java
+++ b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/XMLConfiguration.java
@@ -103,12 +103,14 @@
import static org.jdiameter.client.impl.helpers.Parameters.RealmEntry;
import static org.jdiameter.client.impl.helpers.Parameters.RealmTable;
import static org.jdiameter.client.impl.helpers.Parameters.RecTimeOut;
+import static org.jdiameter.client.impl.helpers.Parameters.RetransmissionRequiredResCodes;
import static org.jdiameter.client.impl.helpers.Parameters.SDEnableSessionCreation;
import static org.jdiameter.client.impl.helpers.Parameters.SDName;
import static org.jdiameter.client.impl.helpers.Parameters.SDProtocol;
import static org.jdiameter.client.impl.helpers.Parameters.SDUseClientMode;
import static org.jdiameter.client.impl.helpers.Parameters.Security;
import static org.jdiameter.client.impl.helpers.Parameters.SecurityRef;
+import static org.jdiameter.client.impl.helpers.Parameters.SessionTimeOut;
import static org.jdiameter.client.impl.helpers.Parameters.Statistics;
import static org.jdiameter.client.impl.helpers.Parameters.StatisticsActiveList;
import static org.jdiameter.client.impl.helpers.Parameters.StatisticsEnabled;
@@ -123,6 +125,7 @@
import static org.jdiameter.client.impl.helpers.Parameters.ThreadPoolPriority;
import static org.jdiameter.client.impl.helpers.Parameters.ThreadPoolSize;
import static org.jdiameter.client.impl.helpers.Parameters.TrustData;
+import static org.jdiameter.client.impl.helpers.Parameters.TxTimeOut;
import static org.jdiameter.client.impl.helpers.Parameters.UseUriAsFqdn;
import static org.jdiameter.client.impl.helpers.Parameters.VendorId;
import static org.jdiameter.server.impl.helpers.ExtensionPoint.InternalNetWork;
@@ -364,6 +367,9 @@ else if (nodeName.equals("DpaTimeOut")) {
else if (nodeName.equals("RecTimeOut")) {
add(RecTimeOut, getLongValue(c.item(i)));
}
+ else if (nodeName.equals("SessionTimeOut")) {
+ add(SessionTimeOut, getLongValue(c.item(i)));
+ }
else if (nodeName.equals("BindDelay")) {
add(BindDelay, getLongValue(c.item(i)));
}
@@ -385,12 +391,29 @@ else if (nodeName.equals("Dictionary")) {
else if (nodeName.equals("RequestTable")) {
addRequestTable(RequestTable, c.item(i));
}
+ else if (nodeName.equals("TxTimeOut")) {
+ add(TxTimeOut, getLongValue(c.item(i)));
+ }
+ else if (nodeName.equals("RetransmissionRequiredResCodes")) {
+ addRetransmissionRequiredResCodes(c.item(i));
+ }
else {
appendOtherParameter(c.item(i));
}
}
}
+ protected void addRetransmissionRequiredResCodes(Node node) {
+ String[] codesArray = getValue(node).replaceAll(" ", "").split(",");
+ if (codesArray.length > 0) {
+ int[] parsedCodesArray = new int[codesArray.length];
+ for (int i = 0; i < codesArray.length; i++) {
+ parsedCodesArray[i] = Integer.parseInt(codesArray[i]);
+ }
+ add(RetransmissionRequiredResCodes, parsedCodesArray);
+ }
+ }
+
protected void addThreadPool(Node item) {
AppConfiguration threadPoolConfiguration = org.jdiameter.client.impl.helpers.EmptyConfiguration.getInstance();
NamedNodeMap attributes = item.getAttributes();
@@ -453,7 +476,8 @@ protected void addStatisticLogger(org.jdiameter.client.impl.helpers.Parameters n
String active_records;
if (node.getAttributes().getNamedItem("active_records") != null) {
active_records = node.getAttributes().getNamedItem("active_records").getNodeValue();
- } else {
+ }
+ else {
active_records = (String) StatisticsActiveList.defValue();
}
add(name,
@@ -553,6 +577,7 @@ protected Configuration addSecurityData(Node node) {
}
return sd;
}
+
protected void addNetwork(Node node) {
NodeList c = node.getChildNodes();
for (int i = 0; i < c.getLength(); i++) {
diff --git a/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-client.xsd b/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-client.xsd
index d283ced65..9ed0d610f 100644
--- a/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-client.xsd
+++ b/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-client.xsd
@@ -167,6 +167,14 @@
+
+
+ Session idle time out in milliseconds.
+
+
+
+
+
Default stop time out in milliseconds.
@@ -215,6 +223,22 @@
+
+
+ Tx timer as described in chapter 13. of RFC 4006 defined in miliseconds.
+
+
+
+
+
+
+
+ Comma delimited list of result codes which make an initial request to be retransmitted.
+
+
+
+
+
Peer FSM Thread Count.
diff --git a/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-server.xsd b/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-server.xsd
index b30936af1..5b02b2ec5 100644
--- a/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-server.xsd
+++ b/core/jdiameter/impl/src/main/resources/META-INF/jdiameter-server.xsd
@@ -77,7 +77,8 @@
-
+
+
@@ -232,6 +233,14 @@
+
+
+ Session idle time out in milliseconds.
+
+
+
+
+
Default stop time out in milliseconds.
@@ -280,6 +289,22 @@
+
+
+ Tx timer as described in chapter 13. of RFC 4006 defined in miliseconds.
+
+
+
+
+
+
+
+ Comma delimited list of result codes which make an initial request to be retransmitted.
+
+
+
+
+
Server Socket bind delay in milliseconds.
diff --git a/core/mux/common/config/jdiameter-config.xml b/core/mux/common/config/jdiameter-config.xml
index e14fcc062..af620828c 100644
--- a/core/mux/common/config/jdiameter-config.xml
+++ b/core/mux/common/config/jdiameter-config.xml
@@ -78,6 +78,7 @@
+
diff --git a/core/mux/common/config/jdiameter-config_baseline.xml b/core/mux/common/config/jdiameter-config_baseline.xml
new file mode 100644
index 000000000..e14fcc062
--- /dev/null
+++ b/core/mux/common/config/jdiameter-config_baseline.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/mux/common/config/jdiameter-config_ext_routing_failover.xml b/core/mux/common/config/jdiameter-config_ext_routing_failover.xml
new file mode 100644
index 000000000..0be6654c4
--- /dev/null
+++ b/core/mux/common/config/jdiameter-config_ext_routing_failover.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexer.java b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexer.java
index d033edf2e..f9785ba6a 100644
--- a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexer.java
+++ b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexer.java
@@ -58,9 +58,11 @@
import static org.jdiameter.client.impl.helpers.Parameters.RealmEntry;
import static org.jdiameter.client.impl.helpers.Parameters.RealmTable;
import static org.jdiameter.client.impl.helpers.Parameters.RecTimeOut;
+import static org.jdiameter.client.impl.helpers.Parameters.RetransmissionRequiredResCodes;
import static org.jdiameter.client.impl.helpers.Parameters.StatisticsLoggerDelay;
import static org.jdiameter.client.impl.helpers.Parameters.StatisticsLoggerPause;
import static org.jdiameter.client.impl.helpers.Parameters.StopTimeOut;
+import static org.jdiameter.client.impl.helpers.Parameters.TxTimeOut;
import static org.jdiameter.client.impl.helpers.Parameters.UseUriAsFqdn;
import static org.jdiameter.server.impl.helpers.Parameters.AcceptUndefinedPeer;
import static org.jdiameter.server.impl.helpers.Parameters.DuplicateTimer;
@@ -103,6 +105,7 @@
import org.jdiameter.api.Request;
import org.jdiameter.api.ResultCode;
import org.jdiameter.api.Session;
+import org.jdiameter.api.SessionPersistenceStorage;
import org.jdiameter.api.Stack;
import org.jdiameter.client.api.controller.IRealm;
import org.jdiameter.client.api.controller.IRealmTable;
@@ -584,6 +587,7 @@ public void unregisterListener(DiameterListener listener) {
* n QueueSize
*/
+ private static final String NEW_LINE = System.getProperty("line.separator");
private final String DEFAULT_STRING = "default_string";
private MutableConfiguration getMutableConfiguration() throws MBeanException {
@@ -849,6 +853,23 @@ public void _Parameters_setRecTimeout(long stopTimeout) throws MBeanException {
getMutableConfiguration().setLongValue(RecTimeOut.ordinal(), stopTimeout);
}
+ public void _Parameters_setTxTimeout(long txTimeout) throws MBeanException {
+ getMutableConfiguration().setLongValue(TxTimeOut.ordinal(), txTimeout);
+ }
+
+ public void _Parameters_setRetransmissionRequiredResCodes(String resCodes) throws MBeanException {
+ if(resCodes != null && resCodes.length() > 0) {
+ String[] codesArray = resCodes.replaceAll(" ", "").split(",");
+ if(codesArray.length > 0) {
+ int[] parsedCodesArray = new int[codesArray.length];
+ for(int i=0; i < codesArray.length; i++) {
+ parsedCodesArray[i] = Integer.parseInt(codesArray[i]);
+ }
+ getMutableConfiguration().setIntArrayValue(RetransmissionRequiredResCodes.ordinal(), parsedCodesArray);
+ }
+ }
+ }
+
@Override
public void _Parameters_setConcurrentEntity(String name, String desc, Integer size) throws MBeanException {
for (Configuration c : getMutableConfiguration().getChildren(Concurrent.ordinal())) {
@@ -989,5 +1010,23 @@ public boolean _Network_Peers_isPeerConnected(String name) throws MBeanException
}
}
+ public String _Network_Sessions_getPersistenceMap(int maxLimit) throws MBeanException {
+ try {
+ SessionPersistenceStorage sds = stack.getSessionPersistenceStorage();
+ if(sds == null) {
+ return "Session persistence is not supported in current configuration!!";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ List sessions = sds.dumpStickySessions(maxLimit);
+ for(String session : sessions) {
+ sb.append(session).append(NEW_LINE);
+ }
+ return sb.length() > 0 ? sb.toString() : "No sessions found";
+ }
+ catch (Exception e) {
+ throw new MBeanException(e, "Failed to get session storage");
+ }
+ }
}
diff --git a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexerMBean.java b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexerMBean.java
index 8599ac34f..956a641f7 100644
--- a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexerMBean.java
+++ b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackMultiplexerMBean.java
@@ -207,6 +207,23 @@ public interface DiameterStackMultiplexerMBean extends ServiceMBean {
*/
void _Parameters_setRecTimeout(long recTimeout) throws MBeanException;
+ /**
+ * Sets the waiting time in the client in the Pending state. (default: 10000, 10 seconds).
+ *
+ * @param txTimeout the amount of time, in ms.
+ * @throws MBeanException if the operation is unable to perform correctly
+ */
+ void _Parameters_setTxTimeout(long txTimeout) throws MBeanException;
+
+ /**
+ * Defines a list of result codes which make an initial request to be retransmitted to
+ * another remote peer.
+ *
+ * @param resCodes comma delimited list of result codes
+ * @throws MBeanException if the operation is unable to perform correctly
+ */
+ void _Parameters_setRetransmissionRequiredResCodes(String resCodes) throws MBeanException;
+
void _Parameters_setConcurrentEntity(String name, String desc, Integer size) throws MBeanException;
void _Parameters_setStatisticLoggerDelay(long delay) throws MBeanException;
@@ -337,4 +354,14 @@ void _Network_Realms_addRealm(String name, String peers, long appVendorId, long
boolean _Network_Peers_isPeerConnected(String name) throws MBeanException;
+ // Sessions : routing persistence map ------------------------------------
+
+ /**
+ * Gets the current state of session persistence map used for routing and lists
+ * all sticky sessions that are currently in operation.
+ *
+ * @param maxLimit maximum number of records to be listed (0 corresponds to no limit)
+ * @throws MBeanException if the operation is unable to perform correctly
+ */
+ String _Network_Sessions_getPersistenceMap(int maxLimit) throws MBeanException;
}
diff --git a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackProxy.java b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackProxy.java
index 4269380ff..6b9d0310e 100644
--- a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackProxy.java
+++ b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/DiameterStackProxy.java
@@ -57,6 +57,7 @@
import org.jdiameter.api.NetworkReqListener;
import org.jdiameter.api.RouteException;
import org.jdiameter.api.SessionFactory;
+import org.jdiameter.api.SessionPersistenceStorage;
import org.jdiameter.api.Stack;
import org.jdiameter.api.validation.Dictionary;
import org.jdiameter.client.api.IAssembler;
@@ -174,6 +175,11 @@ public IAssembler getAssemblerFacility() {
return ((IContainer) realStack).getAssemblerFacility();
}
+ @Override
+ public SessionPersistenceStorage getSessionPersistenceStorage() {
+ return ((IContainer)realStack).getSessionPersistenceStorage();
+ }
+
/* (non-Javadoc)
* @see org.jdiameter.api.Stack#getDictionary()
*/
diff --git a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/Parameters.java b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/Parameters.java
index 3e60ed1e7..a073050cb 100644
--- a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/Parameters.java
+++ b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/Parameters.java
@@ -95,6 +95,10 @@ public interface Parameters extends Serializable {
void setRecTimeout(long recTimeout);
+ long getTxTimeout();
+
+ void setTxTimeout(long txTimeout);
+
/* Gone since merge with build-350
public String getThreadPool_Priority();
diff --git a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/ParametersImpl.java b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/ParametersImpl.java
index 17f29e8f7..c5b8e1293 100644
--- a/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/ParametersImpl.java
+++ b/core/mux/jar/src/main/java/org/mobicents/diameter/stack/management/ParametersImpl.java
@@ -53,9 +53,11 @@
import static org.jdiameter.client.impl.helpers.Parameters.MessageTimeOut;
import static org.jdiameter.client.impl.helpers.Parameters.QueueSize;
import static org.jdiameter.client.impl.helpers.Parameters.RecTimeOut;
+import static org.jdiameter.client.impl.helpers.Parameters.RetransmissionRequiredResCodes;
import static org.jdiameter.client.impl.helpers.Parameters.StatisticsLoggerDelay;
import static org.jdiameter.client.impl.helpers.Parameters.StatisticsLoggerPause;
import static org.jdiameter.client.impl.helpers.Parameters.StopTimeOut;
+import static org.jdiameter.client.impl.helpers.Parameters.TxTimeOut;
import static org.jdiameter.client.impl.helpers.Parameters.UseUriAsFqdn;
import static org.jdiameter.server.impl.helpers.Parameters.AcceptUndefinedPeer;
import static org.jdiameter.server.impl.helpers.Parameters.DuplicateProtection;
@@ -63,6 +65,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
import java.util.HashMap;
import org.jdiameter.api.Configuration;
@@ -93,6 +96,8 @@ public class ParametersImpl implements Parameters {
private long dwaTimeout;
private long dpaTimeout;
private long recTimeout;
+ private long txTimeout;
+ private String retransmissionRequiredResCodes;
// Gone since merge with build-350
// private String threadPool_Priority;
@@ -119,6 +124,8 @@ public ParametersImpl(MutableConfiguration config) {
this.dwaTimeout = config.getLongValue(DwaTimeOut.ordinal(), 10000L);
this.dpaTimeout = config.getLongValue(DpaTimeOut.ordinal(), 5000L);
this.recTimeout = config.getLongValue(RecTimeOut.ordinal(), 10000L);
+ this.txTimeout = config.getLongValue(TxTimeOut.ordinal(), 10000);
+ this.retransmissionRequiredResCodes = Arrays.toString(config.getIntArrayValue(RetransmissionRequiredResCodes.ordinal(), null));
// Concurrent Entities
for (Configuration concurrentEntity : config.getChildren(Concurrent.ordinal())) {
@@ -253,6 +260,22 @@ public void setRecTimeout(long recTimeout) {
DiameterConfiguration.getMutableConfiguration().setLongValue(RecTimeOut.ordinal(), recTimeout);
}
+ public long getTxTimeout() {
+ return txTimeout;
+ }
+
+ public void setTxTimeout(long txTimeout) {
+ DiameterConfiguration.getMutableConfiguration().setLongValue(TxTimeOut.ordinal(), txTimeout);
+ }
+
+ public String getRetransmissionRequiredResCodes() {
+ return retransmissionRequiredResCodes;
+ }
+
+ public void setTxTimeout(int[] resCodes) {
+ DiameterConfiguration.getMutableConfiguration().setIntArrayValue(RetransmissionRequiredResCodes.ordinal(), resCodes);
+ }
+
/* Gone since merge with build-350
public String getThreadPool_Priority() {
return threadPool_Priority;
diff --git a/core/mux/pom.xml b/core/mux/pom.xml
index 242066793..442de5580 100644
--- a/core/mux/pom.xml
+++ b/core/mux/pom.xml
@@ -17,6 +17,8 @@
1.5.9.0-build538-SNAPSHOT
1.1.0-SNAPSHOT
+
+ jdiameter-config_baseline.xml
pom
@@ -93,6 +95,12 @@
sar-jboss-7
+
+ failover-config-enabled
+
+ jdiameter-config_ext_routing_failover.xml
+
+
diff --git a/core/mux/sar-jboss-4/pom.xml b/core/mux/sar-jboss-4/pom.xml
index 7b6ab17bd..72fe74248 100644
--- a/core/mux/sar-jboss-4/pom.xml
+++ b/core/mux/sar-jboss-4/pom.xml
@@ -45,6 +45,16 @@
../common/config
false
+
+ jdiameter-config_*.xml
+
+
+
+ ../common/config
+ false
+
+ ${jdiameter.mux.config.file}
+