From b0ebcd2992de6508a7cacb01b9a3bc94d0f73cd2 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 22 Jun 2017 16:29:42 +0200 Subject: [PATCH 01/26] updated failover logic to ease merging --- .gitignore | 43 +- .../ro/ClientRoSessionDataReplicatedImpl.java | 48 +- .../java/org/jdiameter/api/Configuration.java | 10 + .../jdiameter/api/MutableConfiguration.java | 7 + .../api/NoMorePeersAvailableException.java | 103 +++++ .../java/org/jdiameter/api/RequestType.java | 56 +++ .../api/SessionPersistenceStorage.java | 38 ++ .../main/java/org/jdiameter/api/Stack.java | 7 + .../api/ro/ClientRoSessionListener.java | 45 ++ .../org/jdiameter/client/api/IContainer.java | 3 +- .../org/jdiameter/client/api/IMessage.java | 67 +++ .../client/api/controller/IPeerTable.java | 3 +- .../jdiameter/client/api/router/IRouter.java | 9 +- .../org/jdiameter/client/impl/StackImpl.java | 10 + .../impl/app/cca/ClientCCASessionImpl.java | 46 +- .../app/ro/ClientRoSessionDataLocalImpl.java | 29 +- .../impl/app/ro/ClientRoSessionImpl.java | 434 +++++++++++++++--- .../jdiameter/client/impl/app/ro/Event.java | 2 +- .../impl/app/ro/IClientRoSessionData.java | 10 + .../client/impl/controller/PeerImpl.java | 12 +- .../impl/helpers/EmptyConfiguration.java | 7 + .../client/impl/helpers/Parameters.java | 24 + .../client/impl/helpers/XMLConfiguration.java | 31 +- .../client/impl/parser/MessageImpl.java | 41 +- .../impl/router/FailureAwareRouter.java | 392 ++++++++++++++++ .../client/impl/router/RouterImpl.java | 32 +- .../impl/router/WeightedRoundRobinRouter.java | 26 +- .../transport/tcp/TCPClientConnection.java | 9 + .../api/app/ro/IClientRoSessionContext.java | 3 + .../data/IRoutingAwareSessionDatasource.java | 68 +++ .../impl/app/AppRoutingAwareSessionImpl.java | 165 +++++++ .../impl/app/cca/AppCCASessionImpl.java | 9 +- .../impl/app/cca/CCASessionFactoryImpl.java | 6 +- .../common/impl/app/ro/AppRoSessionImpl.java | 9 +- .../impl/app/ro/RoSessionFactoryImpl.java | 38 +- .../common/impl/data/LocalDataSource.java | 35 +- .../impl/data/RoutingAwareDataSource.java | 203 ++++++++ .../server/impl/FailureAwareRouter.java | 41 ++ .../server/impl/MutablePeerTableImpl.java | 44 +- .../org/jdiameter/server/impl/PeerImpl.java | 5 +- .../impl/app/cca/ServerCCASessionImpl.java | 2 +- .../impl/app/ro/ServerRoSessionImpl.java | 2 +- .../impl/helpers/EmptyConfiguration.java | 16 + .../server/impl/helpers/XMLConfiguration.java | 31 +- .../resources/META-INF/jdiameter-client.xsd | 32 ++ .../resources/META-INF/jdiameter-server.xsd | 32 ++ .../config/jdiameter-config_baseline.xml | 136 ++++++ .../jdiameter-config_ext_routing_failover.xml | 102 ++++ .../stack/DiameterStackMultiplexer.java | 49 ++ .../stack/DiameterStackMultiplexerMBean.java | 47 ++ .../diameter/stack/DiameterStackProxy.java | 6 + .../diameter/stack/management/Parameters.java | 8 + .../stack/management/ParametersImpl.java | 45 ++ core/mux/pom.xml | 8 + core/mux/sar-jboss-4/pom.xml | 11 + core/mux/sar-jboss-5/pom.xml | 13 +- core/mux/sar-jboss-7/pom.xml | 7 +- 57 files changed, 2574 insertions(+), 143 deletions(-) create mode 100644 core/jdiameter/api/src/main/java/org/jdiameter/api/NoMorePeersAvailableException.java create mode 100644 core/jdiameter/api/src/main/java/org/jdiameter/api/RequestType.java create mode 100644 core/jdiameter/api/src/main/java/org/jdiameter/api/SessionPersistenceStorage.java create mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java create mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/common/api/data/IRoutingAwareSessionDatasource.java create mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java create mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/data/RoutingAwareDataSource.java create mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/FailureAwareRouter.java create mode 100644 core/mux/common/config/jdiameter-config_baseline.xml create mode 100644 core/mux/common/config/jdiameter-config_ext_routing_failover.xml diff --git a/.gitignore b/.gitignore index cdfed9175..c57e92307 100644 --- a/.gitignore +++ b/.gitignore @@ -1,30 +1,47 @@ -# Java compiled # -################# +######## Java compiled ######### +################################ *.class -# Eclipse # -########### +########### Eclipse ############ +################################ .classpath .project .settings -# IntelliJ IDEA # -################# -.idea/ +######## IntelliJ IDEA ######### +################################ +.idea *.iml *.iws -# Maven # -######### +########## NetBeans ############ +################################ +nbactions.xml + +# Mobile Tools for Java (J2ME) # +################################ +.mtj.tmp + +############ Maven ############# +################################ target +*.jar +*.war +*.ear -# OS generated files # -###################### +###### OS generated files ###### +################################ +.directory +.Trashes +._* +*~ .DS_Store .DS_Store? -._* .Spotlight-V100 -.Trashes Icon? ehthumbs.db Thumbs.db + +######## VM crash logs ######### +################################ +hs_err_pid* diff --git a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java index f1a150ac0..91314f0de 100644 --- a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java +++ b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java @@ -62,9 +62,9 @@ import org.slf4j.LoggerFactory; /** - * * @author Bartosz Baranowski * @author Alexandre Mendonca + * @author Grzegorz Figiel (ProIDS sp. z o.o.) */ public class ClientRoSessionDataReplicatedImpl extends AppSessionDataReplicatedImpl implements IClientRoSessionData { @@ -74,18 +74,20 @@ public class ClientRoSessionDataReplicatedImpl extends AppSessionDataReplicatedI private static final String REQUEST_TYPE = "REQUEST_TYPE"; private static final String STATE = "STATE"; private static final String TXTIMER_ID = "TXTIMER_ID"; + private static final String RETRANSMISSION_TIMER_ID = "RETRANSMISSION_TIMER_ID"; private static final String TXTIMER_REQUEST = "TXTIMER_REQUEST"; private static final String BUFFER = "BUFFER"; private static final String GRA = "GRA"; private static final String GDDFH = "GDDFH"; private static final String GCCFH = "GCCFH"; + private static final String GCCSF = "GCCSF"; private IMessageParser messageParser; /** * @param nodeFqn * @param mobicentsCluster - * @param iface + * @param container */ public ClientRoSessionDataReplicatedImpl(Fqn nodeFqn, MobicentsCluster mobicentsCluster, IContainer container) { super(nodeFqn, mobicentsCluster); @@ -101,7 +103,7 @@ public ClientRoSessionDataReplicatedImpl(Fqn nodeFqn, MobicentsCluster mobice /** * @param sessionId * @param mobicentsCluster - * @param iface + * @param container */ public ClientRoSessionDataReplicatedImpl(String sessionId, MobicentsCluster mobicentsCluster, IContainer container) { this(Fqn.fromRelativeElements(ReplicatedSessionDatasource.SESSIONS_FQN, sessionId), mobicentsCluster, container); @@ -187,6 +189,26 @@ public void setTxTimerId(Serializable txTimerId) { } } + @Override + public Serializable getRetransmissionTimerId() { + if (exists()) { + return (Serializable) getNode().get(RETRANSMISSION_TIMER_ID); + } + else { + throw new IllegalStateException(); + } + } + + @Override + public void setRetransmissionTimerId(Serializable txTimerId) { + if (exists()) { + getNode().put(RETRANSMISSION_TIMER_ID, txTimerId); + } + else { + throw new IllegalStateException(); + } + } + @Override public Request getTxTimerRequest() { if (exists()) { @@ -323,4 +345,24 @@ public void setGatheredDDFH(int gatheredDDFH) { } } + @Override + public int getGatheredCCSF() { + if (exists()) { + return toPrimitive((Integer) getNode().get(GCCSF)); + } + else { + throw new IllegalStateException(); + } + } + + @Override + public void setGatheredCCSF(int gatheredCCSF) { + if (exists()) { + getNode().put(GCCSF, gatheredCCSF); + } + else { + throw new IllegalStateException(); + } + } + } diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/Configuration.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/Configuration.java index 14c99d5de..d0311bd66 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/Configuration.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/Configuration.java @@ -105,6 +105,16 @@ public interface Configuration { */ byte[] getByteArrayValue(int key, byte[] defaultValue); + /** + * Returns the int[] point value of the given key. + * + * @param key the key + * @param defaultValue the Default Value + * @return the value, or defaultValue if the key was not found or was found + * but was not a int[] point number + */ + int[] getIntArrayValue(int key, int[] defaultValue); + /** * Returns the boolean point value of the given key. * diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/MutableConfiguration.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/MutableConfiguration.java index 0a41f0419..966c8b678 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/MutableConfiguration.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/MutableConfiguration.java @@ -86,6 +86,13 @@ public interface MutableConfiguration extends Configuration { */ void setByteArrayValue(int key, byte[] value); + /** + * Set int array value to configuration + * @param key key of value + * @param value int array value + */ + void setIntArrayValue(int key, int[] value); + /** * Set boolean value to configuration * @param key key of value diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/NoMorePeersAvailableException.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/NoMorePeersAvailableException.java new file mode 100644 index 000000000..f2f5a2e5b --- /dev/null +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/NoMorePeersAvailableException.java @@ -0,0 +1,103 @@ +/* + * 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.api; + +/** + * Signals that no peer is available for routing. + * + * @author ProIDS sp. z o.o. + */ +public class NoMorePeersAvailableException extends RouteException { + + private static final long serialVersionUID = 1L; + + private boolean sessionPersistentRoutingEnabled = false; + private int lastSelectedPeerRating = -1; + private String roundRobinContextDescription = null; + + /** + * Constructor with reason string and routing details + * + * @param message reason string + */ + public NoMorePeersAvailableException(String message, boolean spre, String rrcd, int lspr) { + super(message); + this.setSessionPersistentRoutingEnabled(spre); + this.setRoundRobinContextDescription(rrcd); + this.setLastSelectedPeerRating(lspr); + } + + /** + * Constructor with reason string and parent exception + * + * @param message message reason string + * @param cause parent exception + */ + public NoMorePeersAvailableException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructor with reason string + * + * @param message reason string + */ + public NoMorePeersAvailableException(String message) { + super(message); + } + + public boolean isSessionPersistentRoutingEnabled() { + return sessionPersistentRoutingEnabled; + } + + public void setSessionPersistentRoutingEnabled(boolean sessionPersistentRoutingEnabled) { + this.sessionPersistentRoutingEnabled = sessionPersistentRoutingEnabled; + } + + public String getRoundRobinContextDescription() { + return roundRobinContextDescription; + } + + public void setRoundRobinContextDescription(String roundRobinContextDescription) { + this.roundRobinContextDescription = roundRobinContextDescription; + } + + public int getLastSelectedPeerRating() { + return lastSelectedPeerRating; + } + + public void setLastSelectedPeerRating(int lastSelectedPeerRating) { + this.lastSelectedPeerRating = lastSelectedPeerRating; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder + .append("NoMorePeersAvailableException [sessionPersistentRoutingEnabled=") + .append(sessionPersistentRoutingEnabled) + .append(", lastSelectedPeerRating=").append(lastSelectedPeerRating) + .append(", roundRobinContextDescription=") + .append(roundRobinContextDescription) + .append(", message=").append(getMessage()) + .append("]"); + return builder.toString(); + } +} diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/RequestType.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/RequestType.java new file mode 100644 index 000000000..d82affae3 --- /dev/null +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/RequestType.java @@ -0,0 +1,56 @@ +/* + * 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.api; + +/** + * This enumerated class defines CC-Request-Type AVP possible values as described in RFC 4006: + * + *
+ *     The CC-Request-Type AVP (AVP Code 416) is of type Enumerated and
+ *     contains the reason for sending the credit-control request message.
+ *     It MUST be present in all Credit-Control-Request messages.  The
+ *     following values are defined for the CC-Request-Type AVP:
+ *
+ *     INITIAL_REQUEST                 1
+ *     UPDATE_REQUEST                  2
+ *     TERMINATION_REQUEST             3
+ *     EVENT_REQUEST                   4
+ * 
+ */ +public enum RequestType { + INITIAL_REQUEST(1), + UPDATE_REQUEST(2), + TERMINATION_REQUEST(3), + EVENT_REQUEST(4); + + private final int value; + + RequestType(int value) { + this.value = value; + } + + /** + * Gets value of the corresponding constant as defined in RFC + * @return value of the AVP + */ + public int value() { + return this.value; + } +} diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/SessionPersistenceStorage.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/SessionPersistenceStorage.java new file mode 100644 index 000000000..0e9f78fae --- /dev/null +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/SessionPersistenceStorage.java @@ -0,0 +1,38 @@ +/* + * 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.api; + +import java.util.List; + +/** + * Enables to review and supervise the current state of session persistence map that is used + * for routing that preserves sticky sessions paradigm. Read only access is given for + * the sake of safety issues. + */ +public interface SessionPersistenceStorage { + + /** + * Returns a list of all session persistence records that are currently in operation. + * + * @param maxLimit maximum number of records to be listed (0 corresponds to no limit) + * @return list of active records + */ + List dumpStickySessions(int maxLimit); +} diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/Stack.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/Stack.java index c6d28ea88..6e5723118 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/Stack.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/Stack.java @@ -134,6 +134,13 @@ public interface Stack extends Wrapper { */ SessionFactory getSessionFactory() throws IllegalDiameterStateException; + /** + * Return SessionPersistenceStorage instance + * @return SessionPersistenceStorage instance + * @throws IllegalDiameterStateException if stack is not configured + */ + SessionPersistenceStorage getSessionPersistenceStorage(); + /** * Return Dictionary instance * @return Dictionary instance diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java index 59954f0a3..839ff5d95 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java @@ -44,7 +44,9 @@ import org.jdiameter.api.IllegalDiameterStateException; import org.jdiameter.api.InternalException; +import org.jdiameter.api.Message; import org.jdiameter.api.OverloadException; +import org.jdiameter.api.Peer; import org.jdiameter.api.RouteException; import org.jdiameter.api.app.AppAnswerEvent; import org.jdiameter.api.app.AppRequestEvent; @@ -103,6 +105,49 @@ void doReAuthRequest(ClientRoSession session, ReAuthRequest request) void doOtherEvent(AppSession session, AppRequestEvent request, AppAnswerEvent answer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException; + /** + * Notifies this ClientRoSessionListener that message delivery timeout expired and there was no response from + * one of remote peers. + * + * @param session parent application session (FSM) + * @param msg request object + * @throws InternalException The InternalException signals that internal error has occurred. + * @throws IllegalDiameterStateException The IllegalStateException signals that session has incorrect state (invalid). + * @throws RouteException The NoRouteException signals that no route exist for a given realm. + * @throws OverloadException The OverloadException signals that destination host is overloaded. + */ + void doRequestTxTimeout(ClientRoSession session, Message msg, Peer peer) + throws InternalException, IllegalDiameterStateException, RouteException, OverloadException; + + /** + * Notifies this ClientRoSessionListener that message delivery timeout expired and there was no response from + * any of remote peers in spite of numerous retransmissions and performing failover algorithm if enabled. + * + * @param session parent application session (FSM) + * @param msg request object + * @throws InternalException The InternalException signals that internal error has occurred. + * @throws IllegalDiameterStateException The IllegalStateException signals that session has incorrect state (invalid). + * @throws RouteException The NoRouteException signals that no route exist for a given realm. + * @throws OverloadException The OverloadException signals that destination host is overloaded. + */ + void doRequestTimeout(ClientRoSession session, Message msg, Peer peer) + throws InternalException, IllegalDiameterStateException, RouteException, OverloadException; + + /** + * Notifies this ClientRoSessionListener that message cannot be delivered due to lack of remote peers being available at the moment. + * + * @param cause root cause containing detailed description + * @param session parent application session (FSM) + * @param msg request object + * @param peer last remote peer that has been selected for routing + * @throws InternalException The InternalException signals that internal error has occurred. + * @throws IllegalDiameterStateException The IllegalStateException signals that session has incorrect state (invalid). + * @throws RouteException The NoRouteException signals that no route exist for a given realm. + * @throws OverloadException The OverloadException signals that destination host is overloaded. + */ + void doPeerUnavailability(RouteException cause, ClientRoSession session, Message msg, Peer peer) + throws InternalException, IllegalDiameterStateException, RouteException, OverloadException; + /** * Provides with default value of DDFH AVP - this is used when AVP is not present or send * operation fails for some reason.
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IContainer.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IContainer.java index 4f881ee13..8b623a3c0 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IContainer.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IContainer.java @@ -49,6 +49,7 @@ import org.jdiameter.api.Configuration; import org.jdiameter.api.IllegalDiameterStateException; import org.jdiameter.api.NetworkReqListener; +import org.jdiameter.api.NoMorePeersAvailableException; import org.jdiameter.api.RouteException; import org.jdiameter.api.Stack; import org.jdiameter.common.api.concurrent.IConcurrentFactory; @@ -102,7 +103,7 @@ public interface IContainer extends Stack { * @throws IllegalDiameterStateException * @throws IOException */ - void sendMessage(IMessage session) throws RouteException, AvpDataException, IllegalDiameterStateException, IOException; + void sendMessage(IMessage session) throws RouteException, NoMorePeersAvailableException, AvpDataException, IllegalDiameterStateException, IOException; /** diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java index ecdb94c7a..dc3663b07 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java @@ -57,6 +57,8 @@ * @author erick.svenson@yahoo.com * @author Alexandre Mendonca * @author Bartosz Baranowski + * @author Grzegorz Figiel (ProIDS sp. z o.o.) + * @version 1.5.0.1 */ public interface IMessage extends IRequest, IAnswer { @@ -80,38 +82,54 @@ public interface IMessage extends IRequest, IAnswer { */ int STATE_ANSWERED = 3; + /** + * 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; + /** * Return state of message + * * @return state of message */ int getState(); /** * Set new state + * * @param newState new state value */ void setState(int newState); /** * Return header applicationId + * * @return header applicationId */ long getHeaderApplicationId(); /** * Set header message application id + * * @param applicationId header message application id */ void setHeaderApplicationId(long applicationId); /** * Return flags as inteher + * * @return flags as inteher */ int getFlags(); /** * Create timer for request timout procedure + * * @param scheduledFacility timer facility * @param timeOut value of timeout * @param timeUnit time unit @@ -142,48 +160,96 @@ public interface IMessage extends IRequest, IAnswer { /** * Return attached peer + * * @return attached peer */ IPeer getPeer(); /** * Attach message to peer + * * @param peer attached peer */ void setPeer(IPeer peer); /** * Return application id + * * @return application id */ ApplicationId getSingleApplicationId(); /** * Return application id + * * @return application id */ ApplicationId getSingleApplicationId(long id); /** * Check timeout + * * @return true if request has timeout */ boolean isTimeOut(); + /** + * Tells if there are any timers set to monitor potential retransmissions + * + * @return true if potential retransmissions will be handled + */ + boolean isRetransmissionSupervised(); + + /** + * Marks that message to be under supervision timers guarding retransmissions + * + * @param arg true if supervision is active + */ + void setRetransmissionSupervised(boolean arg); + + /** + * Tells if the number of allowed retransmissions for this message is + * already exceeded or not. + * + * @return false if no more retransmissions are allowed + */ + boolean isRetransmissionAllowed(); + + /** + * @return value of CC-Session-Failover AVP. + */ + int getCcSessionFailover(); + + /** + * Sets the number of allowed retransmissions for this message that can be performed + * in case of failure detection. + * + * @param arg number of allowed retransmissions + */ + void setNumberOfRetransAllowed(int arg); + + /** + * Decrements the number of allowed retransmissions for this message. + */ + void decrementNumberOfRetransAllowed(); + /** * Set event listener + * * @param listener event listener */ void setListener(IEventListener listener); /** * Return event listener + * * @return event listener */ IEventListener getEventListener(); /** * Return duplication key of message + * * @return duplication key of message */ String getDuplicationKey(); @@ -198,6 +264,7 @@ public interface IMessage extends IRequest, IAnswer { /** * Create clone object + * * @return clone */ Object clone(); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/controller/IPeerTable.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/controller/IPeerTable.java index c4998c36a..38aff969c 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/controller/IPeerTable.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/controller/IPeerTable.java @@ -48,6 +48,7 @@ import org.jdiameter.api.AvpDataException; import org.jdiameter.api.IllegalDiameterStateException; import org.jdiameter.api.NetworkReqListener; +import org.jdiameter.api.NoMorePeersAvailableException; import org.jdiameter.api.PeerTable; import org.jdiameter.api.RouteException; import org.jdiameter.client.api.IAssembler; @@ -94,7 +95,7 @@ public interface IPeerTable extends PeerTable { * @throws RouteException * @throws AvpDataException */ - void sendMessage(IMessage message) throws IllegalDiameterStateException, IOException, RouteException, AvpDataException; + void sendMessage(IMessage message) throws IllegalDiameterStateException, IOException, RouteException, NoMorePeersAvailableException, AvpDataException; /** * Register session lister diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/router/IRouter.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/router/IRouter.java index f298346d1..b8746da71 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/router/IRouter.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/router/IRouter.java @@ -45,6 +45,7 @@ import org.jdiameter.api.AvpDataException; import org.jdiameter.api.InternalException; import org.jdiameter.api.RouteException; +import org.jdiameter.api.Wrapper; import org.jdiameter.client.api.IAnswer; import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.IRequest; @@ -54,12 +55,13 @@ /** * This class describe Router functionality + * This class describes Router functionality * * @author erick.svenson@yahoo.com * @author Alexandre Mendonca * @author Bartosz Baranowski */ -public interface IRouter { +public interface IRouter extends Wrapper { /** * Return peer from inner peer table by predefined parameters. Fetches peer based on message content, that is HBH or realm/host avp contents. @@ -130,4 +132,9 @@ public interface IRouter { */ boolean updateRoute(IRequest message) throws RouteException, AvpDataException; + /** + * Tells whether session persistence is preserved while making routing decisions among peers. + * @return true if sticky sessions are applied + */ + boolean isSessionAware(); } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/StackImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/StackImpl.java index 82712402d..65e80b8b7 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/StackImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/StackImpl.java @@ -70,6 +70,7 @@ import org.jdiameter.api.PeerTable; import org.jdiameter.api.RouteException; import org.jdiameter.api.SessionFactory; +import org.jdiameter.api.SessionPersistenceStorage; import org.jdiameter.api.app.StateChangeListener; import org.jdiameter.api.validation.Dictionary; import org.jdiameter.api.validation.ValidatorLevel; @@ -404,6 +405,15 @@ public MetaData getMetaData() { return assembler.getComponentInstance(IMetaData.class); } + @Override + public SessionPersistenceStorage getSessionPersistenceStorage() { + if (state == StackState.IDLE) { + throw new IllegalStateException("Session storage not defined"); + } + ISessionDatasource sds = assembler.getComponentInstance(ISessionDatasource.class); + return sds instanceof SessionPersistenceStorage ? (SessionPersistenceStorage) sds : null; + } + @Override @SuppressWarnings("unchecked") public T getSession(String sessionId, Class clazz) throws InternalException { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java index 955f0eeba..888135961 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java @@ -77,6 +77,7 @@ import org.jdiameter.common.api.app.cca.ClientCCASessionState; import org.jdiameter.common.api.app.cca.ICCAMessageFactory; import org.jdiameter.common.api.app.cca.IClientCCASessionContext; +import org.jdiameter.common.api.data.ISessionDatasource; import org.jdiameter.common.impl.app.AppAnswerEventImpl; import org.jdiameter.common.impl.app.AppEventImpl; import org.jdiameter.common.impl.app.AppRequestEventImpl; @@ -121,11 +122,13 @@ public class ClientCCASessionImpl extends AppCCASessionImpl implements ClientCCA private static final int DDFH_TERMINATE_OR_BUFFER = 0; private static final int DDFH_CONTINUE = 1; - // CC-Request-Type Values --------------------------------------------------- + // Requested-Action Values -------------------------------------------------- private static final int DIRECT_DEBITING = 0; private static final int REFUND_ACCOUNT = 1; private static final int CHECK_BALANCE = 2; private static final int PRICE_ENQUIRY = 3; + + // CC-Request-Type --------------------------------------------------------- private static final int EVENT_REQUEST = 4; // Error Codes -------------------------------------------------------------- @@ -147,9 +150,9 @@ public class ClientCCASessionImpl extends AppCCASessionImpl implements ClientCCA temporaryErrorCodes = Collections.unmodifiableSet(tmp); } - public ClientCCASessionImpl(IClientCCASessionData data, ICCAMessageFactory fct, ISessionFactory sf, ClientCCASessionListener lst, - IClientCCASessionContext ctx, StateChangeListener stLst) { - super(sf, data); + public ClientCCASessionImpl(IClientCCASessionData data, ICCAMessageFactory fct, ISessionDatasource sds, ISessionFactory sf, ClientCCASessionListener lst, + IClientCCASessionContext ctx, StateChangeListener stLst) { + super(sds, sf, data); if (lst == null) { throw new IllegalArgumentException("Listener can not be null"); } @@ -351,6 +354,12 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx // New State: OPEN stopTx(); setState(ClientCCASessionState.OPEN); + //Session persistence record shall be created after a peer had answered the + //first (initial) request for that session + if (isSessionPersistenceEnabled()) { + initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); + startSessionInactivityTimer(); + } } else if (isProvisional(resultCode) || isFailure(resultCode)) { handleFailureMessage((JCreditControlAnswer) answer, (JCreditControlRequest) localEvent.getRequest(), eventType); @@ -402,6 +411,9 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Action: Send RAA followed by CC update request, start Tx // New State: PENDING_U startTx((JCreditControlRequest) localEvent.getRequest()); + if (isSessionPersistenceEnabled()) { + startSessionInactivityTimer(); + } setState(ClientCCASessionState.PENDING_UPDATE); try { dispatchEvent(localEvent.getRequest()); @@ -426,6 +438,9 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Event: User service terminated // Action: Send CC termination request // New State: PENDING_T + if (isSessionPersistenceEnabled()) { + stopSessionInactivityTimer(); + } setState(ClientCCASessionState.PENDING_TERMINATION); try { dispatchEvent(localEvent.getRequest()); @@ -626,6 +641,18 @@ public void onTimer(String timerName) { if (timerName.equals(TX_TIMER_NAME)) { new TxTimerTask(this, this.sessionData.getTxTimerRequest()).run(); } + else { + try { + sendAndStateLock.lock(); + super.onTimer(timerName); + } + catch (Exception ex) { + logger.error("Cannot properly handle timer expiry", ex); + } + finally { + sendAndStateLock.unlock(); + } + } } protected void setState(ClientCCASessionState newState) { @@ -647,6 +674,14 @@ protected void setState(ClientCCASessionState newState, boolean release) { this.release(); } stopTx(); + + if (isSessionPersistenceEnabled()) { + stopSessionInactivityTimer(); + if (!release) { + String oldPeer = flushSessionPersistenceContext(); + logger.debug("Session state reset, routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId()); + } + } } } catch (Exception e) { @@ -1105,6 +1140,9 @@ else if (gatheredRequestedAction == REFUND_ACCOUNT) { // Action: Grant service to end user // New State: PENDING_U context.grantAccessOnTxExpire(this); + if (isSessionPersistenceEnabled()) { + stopSessionInactivityTimer(); + } break; case CCFH_TERMINATE: diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionDataLocalImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionDataLocalImpl.java index 8960e7d1c..fd222817c 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionDataLocalImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionDataLocalImpl.java @@ -49,18 +49,18 @@ import org.jdiameter.common.api.app.ro.ClientRoSessionState; /** - * * @author Bartosz Baranowski * @author Alexandre Mendonca + * @author Grzegorz Figiel (ProIDS sp. z o.o.) */ public class ClientRoSessionDataLocalImpl extends AppSessionDataLocalImpl implements IClientRoSessionData { protected boolean isEventBased = true; protected boolean requestTypeSet = false; protected ClientRoSessionState state = ClientRoSessionState.IDLE; - protected Serializable txTimerId; - //protected JCreditControlRequest txTimerRequest; - protected Request txTimerRequest; + protected Serializable txTimerId = null; + protected Serializable retransmissionTimerId = null; + protected Request txTimerRequest = null; // Event Based Buffer //protected Message buffer = null; @@ -70,6 +70,7 @@ public class ClientRoSessionDataLocalImpl extends AppSessionDataLocalImpl implem protected int gatheredCCFH = NON_INITIALIZED; protected int gatheredDDFH = NON_INITIALIZED; + protected int gatheredCCSF = NON_INITIALIZED; /** * @@ -127,6 +128,16 @@ public void setTxTimerRequest(Request txTimerRequest) { this.txTimerRequest = txTimerRequest; } + @Override + public Serializable getRetransmissionTimerId() { + return retransmissionTimerId; + } + + @Override + public void setRetransmissionTimerId(Serializable retransmissionTimerId) { + this.retransmissionTimerId = retransmissionTimerId; + } + @Override public Request getBuffer() { return buffer; @@ -167,4 +178,14 @@ public void setGatheredDDFH(int gatheredDDFH) { this.gatheredDDFH = gatheredDDFH; } + @Override + public int getGatheredCCSF() { + return this.gatheredCCSF; + } + + @Override + public void setGatheredCCSF(int gatheredCCSF) { + this.gatheredCCSF = gatheredCCSF; + } + } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index ca41deedb..e2ea4bacd 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -58,6 +58,7 @@ import org.jdiameter.api.InternalException; import org.jdiameter.api.Message; import org.jdiameter.api.NetworkReqListener; +import org.jdiameter.api.NoMorePeersAvailableException; import org.jdiameter.api.OverloadException; import org.jdiameter.api.Request; import org.jdiameter.api.RouteException; @@ -77,22 +78,30 @@ import org.jdiameter.client.api.ISessionFactory; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.client.api.parser.ParseException; +import org.jdiameter.client.api.router.IRouter; import org.jdiameter.client.impl.app.ro.Event.Type; import org.jdiameter.common.api.app.IAppSessionState; import org.jdiameter.common.api.app.ro.ClientRoSessionState; import org.jdiameter.common.api.app.ro.IClientRoSessionContext; import org.jdiameter.common.api.app.ro.IRoMessageFactory; +import org.jdiameter.common.api.data.ISessionDatasource; import org.jdiameter.common.impl.app.AppAnswerEventImpl; import org.jdiameter.common.impl.app.AppRequestEventImpl; +import org.jdiameter.common.impl.app.auth.ReAuthAnswerImpl; import org.jdiameter.common.impl.app.ro.AppRoSessionImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.jdiameter.client.impl.helpers.Parameters.RetransmissionRequiredResCodes; +import static org.jdiameter.client.impl.helpers.Parameters.RetransmissionTimeOut; +import static org.jdiameter.client.impl.helpers.Parameters.TxTimeOut; + /** * Client Credit-Control Application session implementation * * @author Alexandre Mendonca * @author Bartosz Baranowski + * @author Grzegorz Figiel (ProIDS sp. z o.o.) */ public class ClientRoSessionImpl extends AppRoSessionImpl implements ClientRoSession, NetworkReqListener, EventListener { @@ -107,13 +116,18 @@ public class ClientRoSessionImpl extends AppRoSessionImpl implements ClientRoSes protected transient ClientRoSessionListener listener; protected transient IClientRoSessionContext context; protected transient IMessageParser parser; + protected transient IRouter router; // Tx Timer ----------------------------------------------------------------- - protected static final String TX_TIMER_NAME = "Ro_CLIENT_TX_TIMER"; - protected static final long TX_TIMER_DEFAULT_VALUE = 30 * 60 * 1000; // miliseconds + protected final long txTimerVal; + + // Response Timer ----------------------------------------------------------- + protected static final String RETRANSMISSION_TIMER_NAME = "Ro_CLIENT_RETRANSMISSION_TIMER"; + protected final long retransmissionTimerVal; - protected long[] authAppIds = new long[] { 4 }; + protected long[] authAppIds = new long[]{4}; + protected final Set retrRequiredErrorCodes; // Requested Action + Credit-Control and Direct-Debiting Failure-Handling --- protected static final int CCFH_TERMINATE = 0; @@ -123,11 +137,13 @@ public class ClientRoSessionImpl extends AppRoSessionImpl implements ClientRoSes private static final int DDFH_TERMINATE_OR_BUFFER = 0; private static final int DDFH_CONTINUE = 1; - // CC-Request-Type Values --------------------------------------------------- + // Requested-Action Values -------------------------------------------------- private static final int DIRECT_DEBITING = 0; private static final int REFUND_ACCOUNT = 1; private static final int CHECK_BALANCE = 2; private static final int PRICE_ENQUIRY = 3; + + // CC-Request-Type --------------------------------------------------------- private static final int EVENT_REQUEST = 4; // Error Codes -------------------------------------------------------------- @@ -152,9 +168,9 @@ public class ClientRoSessionImpl extends AppRoSessionImpl implements ClientRoSes // Session Based Queue protected ArrayList eventQueue = new ArrayList(); - public ClientRoSessionImpl(IClientRoSessionData sessionData, IRoMessageFactory fct, ISessionFactory sf, ClientRoSessionListener lst, - IClientRoSessionContext ctx, StateChangeListener stLst) { - super(sf, sessionData); + public ClientRoSessionImpl(IClientRoSessionData sessionData, IRoMessageFactory fct, ISessionDatasource sds, ISessionFactory sf, ClientRoSessionListener + lst, IClientRoSessionContext ctx, StateChangeListener stLst) { + super(sds, sf, sessionData); if (lst == null) { throw new IllegalArgumentException("Listener can not be null"); } @@ -171,10 +187,19 @@ public ClientRoSessionImpl(IClientRoSessionData sessionData, IRoMessageFactory f this.factory = fct; IContainer icontainer = sf.getContainer(); + this.parser = icontainer.getAssemblerFacility().getComponentInstance(IMessageParser.class); + this.router = icontainer.getAssemblerFacility().getComponentInstance(IRouter.class); + this.txTimerVal = icontainer.getConfiguration().getLongValue(TxTimeOut.ordinal(), (Long) TxTimeOut.defValue()); + this.retransmissionTimerVal = icontainer.getConfiguration().getLongValue(RetransmissionTimeOut.ordinal(), (Long) RetransmissionTimeOut.defValue()); - super.addStateChangeNotification(stLst); + Set tmpErrCodes = new HashSet<>(); + for (int val : icontainer.getConfiguration().getIntArrayValue(RetransmissionRequiredResCodes.ordinal(), new int[0])) { + tmpErrCodes.add(new Long(val)); + } + this.retrRequiredErrorCodes = Collections.unmodifiableSet(tmpErrCodes); + super.addStateChangeNotification(stLst); } protected int getLocalCCFH() { @@ -185,9 +210,13 @@ protected int getLocalDDFH() { return sessionData.getGatheredDDFH() >= 0 ? sessionData.getGatheredDDFH() : context.getDefaultDDFHValue(); } - @Override - public void sendCreditControlRequest(RoCreditControlRequest request) - throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + protected boolean isSessionFailoverSupported() { + return sessionData.getGatheredCCSF() > 0; + } + + + public void sendCreditControlRequest(RoCreditControlRequest request) throws InternalException, IllegalDiameterStateException, RouteException, + OverloadException { try { extractFHAVPs(request, null); this.handleEvent(new Event(true, request, null)); @@ -237,7 +266,7 @@ protected boolean handleEventForEventBased(StateEvent event) throws InternalExce // Event: Client or device requests a one-time service // Action: Send CC event request, start Tx // New State: PENDING_E - startTx((RoCreditControlRequest) localEvent.getRequest()); + startTx(localEvent.getRequest().getMessage()); setState(ClientRoSessionState.PENDING_EVENT); try { dispatchEvent(localEvent.getRequest()); @@ -279,6 +308,7 @@ protected boolean handleEventForEventBased(StateEvent event) throws InternalExce } break; case Tx_TIMER_FIRED: + deliverRequestTxTimeout(localEvent.getRequest().getMessage()); handleTxExpires(localEvent.getRequest().getMessage()); break; default: @@ -335,11 +365,17 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx // Event: Client or device requests access/service // Action: Send CC initial request, start Tx // New State: PENDING_I - startTx((RoCreditControlRequest) localEvent.getRequest()); + startTx(localEvent.getRequest().getMessage()); setState(ClientRoSessionState.PENDING_INITIAL); + // RFC 4006: For new credit-control sessions, failover to an alternative + // credit-control server SHOULD be performed if possible. + sessionData.setGatheredCCSF(IMessage.SESSION_FAILOVER_SUPPORTED_VALUE); try { dispatchEvent(localEvent.getRequest()); } + catch (NoMorePeersAvailableException nmpae) { + handlePeerUnavailability(localEvent.getRequest().getMessage(), nmpae); + } catch (Exception e) { // This handles failure to send in PendingI state in FSM table handleSendFailure(e, eventType, localEvent.getRequest().getMessage()); @@ -355,6 +391,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx AppAnswerEvent answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_INITIAL_ANSWER: + sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_I @@ -363,14 +400,34 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx // New State: OPEN stopTx(); setState(ClientRoSessionState.OPEN); + //Session persistence record shall be created after a peer had answered + //the first (initial) request for that session + if (isSessionPersistenceEnabled()) { + initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); + startSessionInactivityTimer(); + } + } + else if (retrRequiredErrorCodes.contains(resultCode)) { + handleRetransmissionDueToError(eventType, localEvent.getRequest().getMessage()); + break; } else if (isProvisional(resultCode) || isFailure(resultCode)) { handleFailureMessage((RoCreditControlAnswer) answer, (RoCreditControlRequest) localEvent.getRequest(), eventType); } + deliverRoAnswer((RoCreditControlRequest) localEvent.getRequest(), (RoCreditControlAnswer) localEvent.getAnswer()); break; case Tx_TIMER_FIRED: - handleTxExpires(localEvent.getRequest().getMessage()); + deliverRequestTxTimeout(localEvent.getRequest().getMessage()); + if (isRetransmissionRequired()) { + handleRetransmissionDueToTimeout(eventType, localEvent.getRequest()); + } + else { + handleRetransmissionFailure((RoCreditControlRequest) localEvent.getRequest()); + } + break; + case RETRANSMISSION_TIMER_FIRED: + handleRetransmissionFailure((RoCreditControlRequest) localEvent.getRequest()); break; case SEND_UPDATE_REQUEST: case SEND_TERMINATE_REQUEST: @@ -413,11 +470,17 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Event: RAR received // Action: Send RAA followed by CC update request, start Tx // New State: PENDING_U - startTx((RoCreditControlRequest) localEvent.getRequest()); + startTx(localEvent.getRequest().getMessage()); + if (isSessionPersistenceEnabled()) { + startSessionInactivityTimer(); + } setState(ClientRoSessionState.PENDING_UPDATE); try { dispatchEvent(localEvent.getRequest()); } + catch (NoMorePeersAvailableException nmpae) { + handlePeerUnavailability(localEvent.getRequest().getMessage(), nmpae); + } catch (Exception e) { // This handles failure to send in PendingI state in FSM table handleSendFailure(e, eventType, localEvent.getRequest().getMessage()); @@ -438,10 +501,19 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Event: User service terminated // Action: Send CC termination request // New State: PENDING_T + + // In all cases start Tx in order to assure failover + startTx(localEvent.getRequest().getMessage()); + if (isSessionPersistenceEnabled()) { + stopSessionInactivityTimer(); + } setState(ClientRoSessionState.PENDING_TERMINATION); try { dispatchEvent(localEvent.getRequest()); } + catch (NoMorePeersAvailableException nmpae) { + handlePeerUnavailability(localEvent.getRequest().getMessage(), nmpae); + } catch (Exception e) { handleSendFailure(e, eventType, localEvent.getRequest().getMessage()); } @@ -468,6 +540,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_UPDATE_ANSWER: + sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_U @@ -477,15 +550,28 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { stopTx(); setState(ClientRoSessionState.OPEN); } + else if (retrRequiredErrorCodes.contains(resultCode)) { + handleRetransmissionDueToError(eventType, localEvent.getRequest().getMessage()); + break; + } else if (isProvisional(resultCode) || isFailure(resultCode)) { handleFailureMessage((RoCreditControlAnswer) answer, (RoCreditControlRequest) localEvent.getRequest(), eventType); } + deliverRoAnswer((RoCreditControlRequest) localEvent.getRequest(), (RoCreditControlAnswer) localEvent.getAnswer()); break; case Tx_TIMER_FIRED: - handleTxExpires(localEvent.getRequest().getMessage()); + deliverRequestTxTimeout(localEvent.getRequest().getMessage()); + if (isRetransmissionRequired()) { + handleRetransmissionDueToTimeout(eventType, localEvent.getRequest()); + } + else { + handleRetransmissionFailure((RoCreditControlRequest) localEvent.getRequest()); + } + break; + case RETRANSMISSION_TIMER_FIRED: + handleRetransmissionFailure((RoCreditControlRequest) localEvent.getRequest()); break; - case SEND_UPDATE_REQUEST: case SEND_TERMINATE_REQUEST: // Current State: PENDING_U @@ -547,9 +633,28 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { //FIXME: Alex broke this, setting back "true" ? //setState(ClientRoSessionState.IDLE, false); + sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + long resultCode = ((AppAnswerEvent) localEvent.getAnswer()).getResultCodeAvp().getUnsigned32(); + if (retrRequiredErrorCodes.contains(resultCode)) { + handleRetransmissionDueToError(eventType, localEvent.getRequest().getMessage()); + break; + } + deliverRoAnswer((RoCreditControlRequest) localEvent.getRequest(), (RoCreditControlAnswer) localEvent.getAnswer()); setState(ClientRoSessionState.IDLE, true); break; + case Tx_TIMER_FIRED: + deliverRequestTxTimeout(localEvent.getRequest().getMessage()); + if (isRetransmissionRequired()) { + handleRetransmissionDueToTimeout(eventType, localEvent.getRequest()); + } + else { + handleRetransmissionFailure((RoCreditControlRequest) localEvent.getRequest()); + } + break; + case RETRANSMISSION_TIMER_FIRED: + handleRetransmissionFailure((RoCreditControlRequest) localEvent.getRequest()); + break; default: logger.warn("Wrong event type ({}) on state {}", eventType, state); break; @@ -596,6 +701,7 @@ public void timeoutExpired(Request request) { if (request.getCommandCode() == RoCreditControlAnswer.code) { try { sendAndStateLock.lock(); + stopTx(); handleSendFailure(null, null, request); } catch (Exception e) { @@ -607,33 +713,55 @@ public void timeoutExpired(Request request) { } } - protected void startTx(RoCreditControlRequest request) { - long txTimerValue = context.getDefaultTxTimerValue(); - if (txTimerValue < 0) { - txTimerValue = TX_TIMER_DEFAULT_VALUE; - } - stopTx(); - - logger.debug("Scheduling TX Timer {}", txTimerValue); - //this.txFuture = scheduler.schedule(new TxTimerTask(this, request), txTimerValue, TimeUnit.SECONDS); + protected void startTx(Message message) { + stopTx(false); + logger.debug("Scheduling Tx timer in [{}] ms", this.txTimerVal); try { - sessionData.setTxTimerRequest((Request) request.getMessage()); - sessionData.setTxTimerId(this.timerFacility.schedule(this.sessionData.getSessionId(), TX_TIMER_NAME, TX_TIMER_DEFAULT_VALUE)); + sessionData.setTxTimerRequest((Request) message); + sessionData.setTxTimerId(this.timerFacility.schedule(this.sessionData.getSessionId(), TX_TIMER_NAME, this.txTimerVal)); } catch (Exception e) { throw new IllegalArgumentException("Failed to store request.", e); } } - protected void stopTx() { + protected void stopTx(boolean stopDependant) { Serializable txTimerId = this.sessionData.getTxTimerId(); if (txTimerId != null) { + if (stopDependant) { + stopFailoverStopTimer(); + } + logger.debug("Stopping Tx timer [{}]", txTimerId); timerFacility.cancel(txTimerId); sessionData.setTxTimerId(null); sessionData.setTxTimerRequest(null); } } + protected void stopTx() { + stopTx(true); + } + + protected void startFailoverStopTimer() { + long timerVal = this.retransmissionTimerVal - this.txTimerVal; + if (timerVal <= 0) { + logger.warn("Value of Tx timer cannot exceed failover stop timer: [{}] vs. [{}] (taking default values)", this.txTimerVal, this.retransmissionTimerVal); + timerVal = this.txTimerVal + (((Long) RetransmissionTimeOut.defValue()) - ((Long) TxTimeOut.defValue())); + } + logger.debug("Scheduling failover stop timer in [{}] ms", timerVal); + stopFailoverStopTimer(); + sessionData.setRetransmissionTimerId(this.timerFacility.schedule(this.sessionData.getSessionId(), RETRANSMISSION_TIMER_NAME, timerVal)); + } + + protected void stopFailoverStopTimer() { + Serializable failoverStopTimerId = this.sessionData.getRetransmissionTimerId(); + if (failoverStopTimerId != null) { + logger.debug("Stopping failover stop timer [{}]", failoverStopTimerId); + timerFacility.cancel(failoverStopTimerId); + sessionData.setRetransmissionTimerId(null); + } + } + /* (non-Javadoc) * @see org.jdiameter.common.impl.app.AppSessionImpl#onTimer(java.lang.String) */ @@ -642,6 +770,21 @@ public void onTimer(String timerName) { if (timerName.equals(TX_TIMER_NAME)) { new TxTimerTask(this, sessionData.getTxTimerRequest()).run(); } + else if (timerName.equals(RETRANSMISSION_TIMER_NAME)) { + new RetransmissionTimerTask(this, sessionData.getTxTimerRequest()).run(); + } + else { + try { + sendAndStateLock.lock(); + super.onTimer(timerName); + } + catch (Exception ex) { + logger.error("Cannot properly handle timer expiry", ex); + } + finally { + sendAndStateLock.unlock(); + } + } } protected void setState(ClientRoSessionState newState) { @@ -655,7 +798,7 @@ protected void setState(ClientRoSessionState newState, boolean release) { IAppSessionState oldState = state; sessionData.setClientRoSessionState(newState); for (StateChangeListener i : stateListeners) { - i.stateChanged(this,(Enum) oldState, (Enum) newState); + i.stateChanged(this, (Enum) oldState, newState); } if (newState == ClientRoSessionState.IDLE) { @@ -663,6 +806,14 @@ protected void setState(ClientRoSessionState newState, boolean release) { this.release(); } stopTx(); + + if (isSessionPersistenceEnabled()) { + stopSessionInactivityTimer(); + if (!release) { + String oldPeer = flushSessionPersistenceContext(); + logger.debug("Session state reset, routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId()); + } + } } } catch (Exception e) { @@ -693,7 +844,10 @@ public void release() { } protected void handleSendFailure(Exception e, Event.Type eventType, Message request) throws Exception { - logger.debug("Failed to send message, type: {} message: {}, failure: {}", new Object[]{eventType, request, e != null ? e.getLocalizedMessage() : ""}); + logger.warn("Failed to send message", e); + if (logger.isDebugEnabled()) { + logger.debug("Failed to send message, type: {} message: {}, failure: {}", new Object[]{eventType, request, e != null ? e.getLocalizedMessage() : ""}); + } try { ClientRoSessionState state = sessionData.getClientRoSessionState(); // Event Based ---------------------------------------------------------- @@ -1141,6 +1295,100 @@ else if (gatheredRequestedAction == REFUND_ACCOUNT) { break; } } + + this.release(); + } + + protected void handleRetransmissionFailure(RoCreditControlRequest req) { + try { + deliverRequestTimeout(req.getMessage()); + resetMessageStatus(req.getMessage()); + } + catch (InternalException e) { + logger.error("Cannot remove the expired message from either peer or rouoter tables for session [{}]", this.getSessionId()); + } + + setState(ClientRoSessionState.IDLE, true); + } + + protected void handlePeerUnavailability(Message msg, NoMorePeersAvailableException nmpae) { + logger.warn("No more peers available for sending diameter message: ", nmpae.getMessage()); + if (logger.isDebugEnabled()) { + logger.debug("nmpa exception: {}", nmpae); + } + deliverPeerUnavailabilityError(msg, nmpae); + resetMessageStatus(msg); + setState(ClientRoSessionState.IDLE, true); + } + + protected void handleRetransmission(Type eventType, IMessage msg, boolean tFlagSetting) { + msg.setReTransmitted(tFlagSetting); + if (this.sessionData.getRetransmissionTimerId() == null) { + startFailoverStopTimer(); + } + + if (isSessionPersistenceEnabled()) { + String oldPeer = flushSessionPersistenceContext(); + logger.debug("Routing context for peer [{}] was removed from session [{}] due to retransmission", oldPeer, this.getSessionId()); + } + + resetMessageStatus(msg); + startTx(msg); + + try { + dispatchEvent(msg); + } + catch (NoMorePeersAvailableException nmpae) { + handlePeerUnavailability(msg, nmpae); + } + catch (Exception e1) { + logger.error("Cannot retransmit an old request", e1); + try { + handleSendFailure(e1, eventType, msg); + } + catch (Exception e2) { + logger.error("Failure handling error", e2); + } + } + } + + protected void handleRetransmissionDueToError(Type eventType, Message msg) { + IMessage imsg = (IMessage) msg; + logger.warn("Message will be retransmitted due to error response [{}] ", msg); + + try { + if (imsg.isRetransmissionAllowed()) { + if (isSessionFailoverSupported()) { + handleRetransmission(eventType, imsg, false); + imsg.decrementNumberOfRetransAllowed(); + } + else { + handleSendFailure(new Exception("Failover unsupported for session ID: " + sessionData.getSessionId()), eventType, msg); + } + } + else { + NoMorePeersAvailableException cause = new NoMorePeersAvailableException("No more peers available for retransmission"); + cause.setSessionPersistentRoutingEnabled(router.isSessionAware()); + handlePeerUnavailability(msg, cause); + } + } + catch (Exception e) { + logger.error("Failure handling send failure error in handleRetransmissionDueToError", e); + } + } + + protected void handleRetransmissionDueToTimeout(Type eventType, AppEvent event) throws InternalException { + if (isSessionFailoverSupported()) { + handleRetransmission(eventType, (IMessage) event.getMessage(), true); + } + else { + logger.warn("Failed to send message. Failover unsupported for session ID: {}", sessionData.getSessionId()); + if (logger.isDebugEnabled()) { + logger.debug("Failed to send message, type: {} message: {}, failure: Failover unsupported for session ID: {}", new Object[]{eventType, event + .getMessage(), sessionData.getSessionId()}); + } + handleRetransmissionFailure((RoCreditControlRequest) event); + } } /** @@ -1184,6 +1432,7 @@ protected void dispatch() { } protected void deliverRoAnswer(RoCreditControlRequest request, RoCreditControlAnswer answer) { + logger.debug("Propagating answer event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { listener.doCreditControlAnswer(this, request, answer); @@ -1194,6 +1443,52 @@ protected void deliverRoAnswer(RoCreditControlRequest request, RoCreditControlAn } } + protected void deliverRAR(ReAuthRequest request) { + logger.debug("Propagating RAR event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); + try { + listener.doReAuthRequest(this, request); + } + catch (Exception e) { + logger.warn("Failure delivering RAR", e); + } + } + + protected void deliverRequestTxTimeout(Message msg) { + logger.debug("Propagating Tx timeout event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); + try { + if (isValid()) { + listener.doRequestTxTimeout(this, msg, ((IMessage) msg).getPeer()); + } + } + catch (Exception e) { + logger.warn("Failure delivering request tx timeout", e); + } + } + + protected void deliverRequestTimeout(Message msg) { + logger.debug("Propagating timeout event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); + try { + if (isValid()) { + listener.doRequestTimeout(this, msg, ((IMessage) msg).getPeer()); + } + } + catch (Exception e) { + logger.warn("Failure delivering request timeout", e); + } + } + + protected void deliverPeerUnavailabilityError(Message msg, NoMorePeersAvailableException cause) { + logger.debug("Propagating peer unavailability error event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); + try { + if (isValid()) { + listener.doPeerUnavailability(cause, this, msg, ((IMessage) msg).getPeer()); + } + } + catch (Exception e) { + logger.warn("Failure delivering peer unavailability error", e); + } + } + protected void extractFHAVPs(RoCreditControlRequest request, RoCreditControlAnswer answer) throws AvpDataException { if (answer != null) { try { @@ -1236,17 +1531,15 @@ else if (request != null) { } } - protected void deliverRAR(ReAuthRequest request) { - try { - listener.doReAuthRequest(this, request); - } - catch (Exception e) { - logger.debug("Failure delivering RAR", e); + protected void dispatchEvent(IMessage message) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + if (message.isRequest()) { + message.setRetransmissionSupervised(true); } + session.send(message, this); } protected void dispatchEvent(AppEvent event) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { - session.send(event.getMessage(), this); + dispatchEvent((IMessage) event.getMessage()); } protected boolean isProvisional(long resultCode) { @@ -1258,7 +1551,12 @@ protected boolean isSuccess(long resultCode) { } protected boolean isFailure(long code) { - return (!isProvisional(code) && !isSuccess(code) && ((code >= 3000 && code < 6000)) && !temporaryErrorCodes.contains(code)); + return (!isProvisional(code) && !isSuccess(code) && ((code >= 3000 && /*code < 4000) || (code >= 5000 &&*/ code < 6000)) && !temporaryErrorCodes.contains + (code)); + } + + protected boolean isRetransmissionRequired() { + return (getLocalCCFH() == CCFH_CONTINUE || getLocalCCFH() == CCFH_RETRY_AND_TERMINATE); } /* (non-Javadoc) @@ -1269,7 +1567,6 @@ public boolean isReplicable() { return true; } - private class TxTimerTask implements Runnable { private ClientRoSession session = null; private Request request = null; @@ -1280,19 +1577,13 @@ private TxTimerTask(ClientRoSession session, Request request) { this.request = request; } - @Override public void run() { try { sendAndStateLock.lock(); - logger.debug("Fired TX Timer"); + logger.debug("Fired Tx timer"); sessionData.setTxTimerId(null); sessionData.setTxTimerRequest(null); - try { - context.txTimerExpired(session); - } - catch (Exception e) { - logger.debug("Failure handling TX Timer Expired", e); - } + RoCreditControlRequest req = factory.createCreditControlRequest(request); handleEvent(new Event(Event.Type.Tx_TIMER_FIRED, req, null)); } @@ -1311,6 +1602,37 @@ public void run() { } } + private class RetransmissionTimerTask implements Runnable { + private Request request = null; + + private RetransmissionTimerTask(ClientRoSession session, Request request) { + super(); + this.request = request; + } + + public void run() { + try { + sendAndStateLock.lock(); + logger.debug("Fired failover stop timer (Retransmission timout occured)"); + stopTx(false); + sessionData.setRetransmissionTimerId(null); + handleEvent(new Event(Event.Type.RETRANSMISSION_TIMER_FIRED, factory.createCreditControlRequest(request), null)); + } + catch (InternalException e) { + logger.error("Internal Exception", e); + } + catch (OverloadException e) { + logger.error("Overload Exception", e); + } + catch (Exception e) { + logger.error("Exception", e); + } + finally { + sendAndStateLock.unlock(); + } + } + } + private Message messageFromBuffer(ByteBuffer request) throws InternalException { if (request != null) { Message m; @@ -1334,15 +1656,24 @@ private ByteBuffer messageToBuffer(IMessage msg) throws InternalException { } } + private void resetMessageStatus(Message message) { + IMessage msg = (IMessage) message; + msg.clearTimer(); + msg.setState(IMessage.STATE_NOT_SENT); + if (msg.getPeer() != null) { + msg.getPeer().remMessage(msg); + } + router.garbageCollectRequestRouteInfo(msg); + } + private class RequestDelivery implements Runnable { ClientRoSession session; Request request; - @Override public void run() { try { switch (request.getCommandCode()) { - case ReAuthAnswer.code: + case ReAuthAnswerImpl.code: handleEvent(new Event(Event.Type.RECEIVED_RAR, factory.createReAuthRequest(request), null)); break; @@ -1362,14 +1693,13 @@ private class AnswerDelivery implements Runnable { Answer answer; Request request; - @Override public void run() { try { switch (request.getCommandCode()) { case RoCreditControlAnswer.code: RoCreditControlRequest _request = factory.createCreditControlRequest(request); RoCreditControlAnswer _answer = factory.createCreditControlAnswer(answer); - extractFHAVPs(null, _answer ); + extractFHAVPs(null, _answer); handleEvent(new Event(false, _request, _answer)); break; diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/Event.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/Event.java index 62ea2ea3a..0285b65e9 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/Event.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/Event.java @@ -61,7 +61,7 @@ public enum Type { SEND_INITIAL_REQUEST, RECEIVED_INITIAL_ANSWER, SEND_UPDATE_REQUEST, RECEIVED_UPDATE_ANSWER, SEND_TERMINATE_REQUEST, RECEIVED_TERMINATED_ANSWER, - RECEIVED_RAR, SEND_RAA, Tx_TIMER_FIRED, + RECEIVED_RAR,SEND_RAA, Tx_TIMER_FIRED, RETRANSMISSION_TIMER_FIRED, SEND_EVENT_REQUEST, RECEIVE_EVENT_ANSWER; } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/IClientRoSessionData.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/IClientRoSessionData.java index a9611a01a..bd8e96008 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/IClientRoSessionData.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/IClientRoSessionData.java @@ -52,6 +52,7 @@ * * @author Bartosz Baranowski * @author Alexandre Mendonca + * @author Grzegorz Figiel (ProIDS sp. z o.o.) */ public interface IClientRoSessionData extends IRoSessionData { @@ -75,6 +76,10 @@ public interface IClientRoSessionData extends IRoSessionData { void setTxTimerRequest(Request txTimerRequest); + Serializable getRetransmissionTimerId(); + + void setRetransmissionTimerId(Serializable retransmissionTimerId); + Request getBuffer(); void setBuffer(Request buffer); @@ -90,4 +95,9 @@ public interface IClientRoSessionData extends IRoSessionData { int getGatheredDDFH(); void setGatheredDDFH(int gatheredDDFH); + + int getGatheredCCSF(); + + void setGatheredCCSF(int gatheredCCSF); + } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java index 3415b6cec..083f92727 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java @@ -72,6 +72,7 @@ import static org.jdiameter.client.api.fsm.EventTypes.INTERNAL_ERROR; import static org.jdiameter.client.api.fsm.EventTypes.RECEIVE_MSG_EVENT; import static org.jdiameter.client.api.fsm.EventTypes.STOP_EVENT; +import static org.jdiameter.client.impl.helpers.Parameters.PeerRating; import static org.jdiameter.client.impl.helpers.Parameters.SecurityRef; import static org.jdiameter.client.impl.helpers.Parameters.UseUriAsFqdn; @@ -191,7 +192,7 @@ public void connectionOpened(String connKey) { public void connectionClosed(String connKey, List notSent) { logger.debug("Connection from {} is closed", uri); for (IMessage request : peerRequests.values()) { - if (request.getState() == IMessage.STATE_SENT) { + if (request.getState() == IMessage.STATE_SENT && !request.isRetransmissionSupervised()) { request.setReTransmitted(true); request.setState(IMessage.STATE_NOT_SENT); try { @@ -273,7 +274,12 @@ protected PeerImpl(final PeerTableImpl table, int rating, URI remotePeer, String IConnection connection, final ISessionDatasource sessionDataSource) throws InternalException, TransportException { super(remotePeer, statisticFactory); this.table = table; - this.rating = rating; + if (peerConfig != null) { + this.rating = peerConfig.getIntValue(PeerRating.ordinal(), 0); + } + else { + this.rating = rating; + } this.router = table.router; this.metaData = metaData; // XXX: FT/HA // this.slc = table.getSessionReqListeners(); @@ -632,7 +638,7 @@ public boolean isConnected() { @Override public String toString() { - return "CPeer{" + "Uri=" + uri + "; State=" + (fsm != null ? fsm.getState(PeerState.class) : "n/a") + "; Con=" + connection + "}"; + return "CPeer{" + "Uri=" + uri + "; State=" + (fsm != null ? fsm.getState(PeerState.class) : "n/a") + "; Rating=" + rating + "; Con=" + connection + "}"; } protected void fillIPAddressTable(IMessage message) { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/EmptyConfiguration.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/EmptyConfiguration.java index 6b9019d6f..37757699d 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/EmptyConfiguration.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/EmptyConfiguration.java @@ -213,6 +213,13 @@ public byte[] getByteArrayValue(int i, byte[] bytes) { * @see org.jdiameter.api.Configuration class */ @Override + public int[] getIntArrayValue(int i, int[] ints) { + return (int[]) (isAttributeExist(i) ? elements.get(i) : ints); + } + + /** + * @see org.jdiameter.api.Configuration class + */ public boolean getBooleanValue(int i, boolean b) { return (Boolean) (isAttributeExist(i) ? elements.get(i) : b); } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java index cb568947d..c07c3b0fa 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java @@ -398,6 +398,30 @@ public class Parameters extends Ordinal { */ public static final Parameters DictionaryReceiveLevel = new Parameters("DictionaryReceiveLevel", String.class, "OFF"); + /** + * Maximum session inactivity time specified in seconds which defines how much time + * the persistence record should be kept if there is no request sent within a session. + * Irrelevant when session persistent routing is not enabled. + */ + public static final Parameters SessionInactivityTimeOut = new Parameters("SessionInactivityTimeOut", Integer.class, 600); + + /** + * Tx timer as described in chapter 13. of RFC 4006: + *
The Tx timer is introduced to control the waiting time in the client in the Pending state. The recommended value is 10 seconds.
+ */ + public static final Parameters TxTimeOut = new Parameters("TxTimeOut", Long.class, 10000L); + + /** + * Retransmission stop timer which defines how long the stack should wait for the answer message from remote peers and carry on with + * retransmissions in case of delivery failures. + */ + public static final Parameters RetransmissionTimeOut = new Parameters("RetransmissionTimeOut", Long.class, 45000L); + + /** + * Array of result codes which make an initial request to be retransmitted to another remote peer. + */ + public static final Parameters RetransmissionRequiredResCodes = new Parameters("RetransmissionRequiredResCodes", Object.class); + /** * Return all parameters as iterator * diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java index 94286661f..f43c64500 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/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.SessionInactivityTimeOut; 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.Parameters.RealmEntryExpTime; @@ -130,6 +133,7 @@ import static org.jdiameter.server.impl.helpers.Parameters.RealmHosts; import static org.jdiameter.server.impl.helpers.Parameters.RealmLocalAction; import static org.jdiameter.server.impl.helpers.Parameters.RealmName; +import static org.jdiameter.server.impl.helpers.Parameters.RetransmissionTimeOut; import java.io.File; import java.io.InputStream; @@ -377,12 +381,35 @@ else if (nodeName.equals("Concurrent")) { else if (nodeName.equals("Dictionary")) { addDictionary(Dictionary, c.item(i)); } + else if (nodeName.equals("SessionInactivityTimeOut")) { + add(SessionInactivityTimeOut, getIntValue(c.item(i))); + } + else if (nodeName.equals("TxTimeOut")) { + add(TxTimeOut, getLongValue(c.item(i))); + } + else if (nodeName.equals("RetransmissionTimeOut")) { + add(RetransmissionTimeOut, 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 addConcurrent(org.jdiameter.client.impl.helpers.Parameters name, Node node) { NodeList c = node.getChildNodes(); List items = new ArrayList(); @@ -716,10 +743,10 @@ else if (nodeName.equals("AgentRedirect")) { addInternalExtension(InternalAgentRedirect, getValue(c.item(i))); } else if (nodeName.equals("AgentConfiguration")) { - add(InternalAgentConfiguration, getValue(c.item(i))) ; + add(InternalAgentConfiguration, getValue(c.item(i))); } else if (nodeName.equals("StatisticProcessor")) { - addInternalExtension(InternalStatisticProcessor, getValue(c.item(i))) ; + addInternalExtension(InternalStatisticProcessor, getValue(c.item(i))); } else { appendOtherExtension(c.item(i)); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java index da48e5617..1b8a9368f 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java @@ -62,12 +62,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; + /** * Represents a Diameter message. * * @author erick.svenson@yahoo.com * @author Alexandre Mendonca * @author Bartosz Baranowski + * @author Grzegorz Figiel (ProIDS sp. z o.o.) */ public class MessageImpl implements IMessage { @@ -87,6 +89,8 @@ public class MessageImpl implements IMessage { AvpSetImpl avpSet; boolean isNetworkRequest = false; + boolean isRetransSupervisionActive = false; + int numberOfRetransAllowed = Integer.MIN_VALUE; transient IPeer peer; transient TimerTask timerTask; @@ -99,7 +103,6 @@ public class MessageImpl implements IMessage { /** * Create empty message * - * @param parser * @param commandCode * @param appId */ @@ -114,7 +117,6 @@ public class MessageImpl implements IMessage { /** * Create empty message * - * @param parser * @param commandCode * @param applicationId * @param flags @@ -266,6 +268,41 @@ public void setReTransmitted(boolean b) { } @Override + public boolean isRetransmissionSupervised() { + return this.isRetransSupervisionActive; + } + + public void setRetransmissionSupervised(boolean arg) { + this.isRetransSupervisionActive = arg; + } + + public boolean isRetransmissionAllowed() { + return this.numberOfRetransAllowed > 0; + } + + public int getCcSessionFailover() { + try { + Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); + if (avpCcSessionFailover != null) { + return avpCcSessionFailover.getInteger32(); + } + } + catch (AvpDataException ade) { + logger.error("Failed to fetch CC-Session-Failover", ade); + } + return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + } + + public void setNumberOfRetransAllowed(int arg) { + if (this.numberOfRetransAllowed < 0) { + this.numberOfRetransAllowed = arg; + } + } + + public void decrementNumberOfRetransAllowed() { + this.numberOfRetransAllowed--; + } + public int getCommandCode() { return this.commandCode; } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java new file mode 100644 index 000000000..c003c1217 --- /dev/null +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java @@ -0,0 +1,392 @@ +/* + * 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.client.impl.router; + +import org.jdiameter.api.Avp; +import org.jdiameter.api.AvpDataException; +import org.jdiameter.api.Configuration; +import org.jdiameter.api.MetaData; +import org.jdiameter.api.NoMorePeersAvailableException; +import org.jdiameter.api.PeerState; +import org.jdiameter.api.RouteException; +import org.jdiameter.client.api.IContainer; +import org.jdiameter.client.api.IMessage; +import org.jdiameter.client.api.controller.IPeer; +import org.jdiameter.client.api.controller.IPeerTable; +import org.jdiameter.client.api.controller.IRealm; +import org.jdiameter.client.api.controller.IRealmTable; +import org.jdiameter.common.api.concurrent.IConcurrentFactory; +import org.jdiameter.common.api.data.IRoutingAwareSessionDatasource; +import org.jdiameter.common.api.data.ISessionDatasource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Extends capabilities of basic router implementation {@link RouterImpl} with extra features + * related to failure detection and failure aware routing. Rating of a particular peer is + * taken into consideration when deciding about an order of peers usage in case of failure + * detection. The highest rating peers are used first, then lower priorities peers next, etc. + * If several peers are marked with the same rating, load balancing algorithm is executed among + * them. In case of all higher priority peers failure, lower priority peers are considered. + * Afterwards, in case any higher priority peer becomes available again, only new sessions requests + * should be targeted again to higher priority peers, i.e. currently handled session stays + * assigned to a peer selected beforehand. + */ +public class FailureAwareRouter extends WeightedRoundRobinRouter { + + private static final Logger logger = LoggerFactory.getLogger(FailureAwareRouter.class); + + private IRoutingAwareSessionDatasource sessionDatasource = null; + + private int lastSelectedRating = -1; + + /** + * 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); + + ISessionDatasource sds = container.getAssemblerFacility().getComponentInstance(ISessionDatasource.class); + if (sds instanceof IRoutingAwareSessionDatasource) { + this.sessionDatasource = (IRoutingAwareSessionDatasource) sds; + } + + logger.debug("Constructor for FailureAwareRouter (session persistent routing {})", isSessionPersistentRoutingEnabled() ? "enabled" : "disabled"); + } + + /** + * Narrows down the subset of peers selected by {@link RouterImpl} superclass to those with + * the highest rating only. + */ + protected List getAvailablePeers(String destRealm, String[] peers, IPeerTable manager, IMessage message) { + List selectedPeers = getAvailablePeers(destRealm, peers, manager, message); + + if (logger.isDebugEnabled()) { + logger.debug("All available peers: {}", selectedPeers); + } + selectedPeers = narrowToAnswerablePeers(selectedPeers, message.getSessionId()); + if (logger.isDebugEnabled()) { + logger.debug("All answerable peers: {}", selectedPeers); + } + + if (message.isRetransmissionSupervised()) { + message.setNumberOfRetransAllowed(selectedPeers.size() - 1); + } + + int maxRating = findMaximumRating(selectedPeers); + if (maxRating >= 0 && maxRating != lastSelectedRating) { + lastSelectedRating = maxRating; + resetRoundRobinContext(); + } + + selectedPeers = narrowToSelectablePeersSubset(selectedPeers, maxRating, message); + if (logger.isDebugEnabled()) { + logger.debug("Final subset of selectable peers (max rating [{}]): {}", maxRating, selectedPeers); + } + + return selectedPeers; + } + + private List narrowToAnswerablePeers(List availablePeers, String sessionId) { + List unAnswerablePeers = sessionDatasource.getUnanswerablePeers(sessionId); + + if (unAnswerablePeers != null) { + for (String peerFqdn : unAnswerablePeers) { + for (IPeer peer : availablePeers) { + if (peer.getUri().getFQDN().equals(peerFqdn)) { + availablePeers.remove(peer); + break; + } + } + } + } + + return availablePeers; + } + + @Override + public IPeer getPeer(IMessage message, IPeerTable manager) throws RouteException, AvpDataException { + logger.debug("Getting a peer for message [{}]", message); + //FIXME: add ability to send without matching realm+peer pair?, that is , route based on peer table entries? + //that is, if msg.destHost != null > getPeer(msg.destHost).sendMessage(msg); + String destRealm = null; + String destHost = null; + IRealm matchedRealm = null; + String[] info = null; + // Get destination information + if (message.isRequest()) { + Avp avpRealm = message.getAvps().getAvp(Avp.DESTINATION_REALM); + if (avpRealm == null) { + throw new RouteException("Destination realm avp is empty"); + } + destRealm = avpRealm.getDiameterIdentity(); + + Avp avpHost = message.getAvps().getAvp(Avp.DESTINATION_HOST); + if (avpHost != null) { + destHost = avpHost.getDiameterIdentity(); + } + if (logger.isDebugEnabled()) { + logger.debug("Looking up peer for request: [{}], DestHost=[{}], DestRealm=[{}]", new Object[] {message, destHost, destRealm}); + } + + matchedRealm = (IRealm) this.realmTable.matchRealm(message); + } + else { + //answer, search + info = getRequestRouteInfo(message); + if (info != null) { + destHost = info[0]; + destRealm = info[1]; + logger.debug("Message is an answer. Host is [{}] and Realm is [{}] as per hopbyhop info from request", destHost, destRealm); + if (destRealm == null) { + logger.warn("Destination-Realm was null for hopbyhop id " + message.getHopByHopIdentifier()); + } + } + else { + logger.debug("No Host and realm found based on hopbyhop id of the answer associated request"); + } + //FIXME: if no info, should not send it ? + //FIXME: add strict deff in route back table so stack does not have to lookup? + if (logger.isDebugEnabled()) { + logger.debug("Looking up peer for answer: [{}], DestHost=[{}], DestRealm=[{}]", new Object[] {message, destHost, destRealm}); + } + matchedRealm = (IRealm) this.realmTable.matchRealm(message, destRealm); + } + + // IPeer peer = getPeerPredProcessing(message, destRealm, destHost); + // + // if (peer != null) { + // logger.debug("Found during preprocessing...[{}]", peer); + // return peer; + // } + + // Check realm name + //TODO: check only if it exists? + if (matchedRealm == null) { + throw new RouteException("Unknown realm name [" + destRealm + "]"); + } + + // THIS IS GET PEER, NOT ROUTE!!!!!!! + // Redirect processing + //redirectProcessing(message, destRealm, destHost); + // Check previous context information, this takes care of most answers. + if (message.getPeer() != null && destHost != null && destHost.equals(message.getPeer().getUri().getFQDN()) && message.getPeer().hasValidConnection()) { + if (logger.isDebugEnabled()) { + logger.debug("Select previous message usage peer [{}]", message.getPeer()); + } + return message.getPeer(); + } + + // Balancing procedure + + IPeer c = destHost != null ? manager.getPeer(destHost) : null; + + if (c != null && c.hasValidConnection()) { + logger.debug("Found a peer using destination host avp [{}] peer is [{}] with a valid connection.", destHost, c); + //here matchedRealm MAY + return c; + } + else { + logger.debug("Finding peer by destination host avp [host={}] did not find anything. Now going to try finding one by destination realm [{}]", + destHost, destRealm); + String[] peers = matchedRealm.getPeerNames(); + if (peers == null || peers.length == 0) { + throw new RouteException("Unable to find context by route information [" + destRealm + " ," + destHost + "]"); + } + + List availablePeers = getAvailablePeers(destRealm, peers, manager, message); + + if (logger.isDebugEnabled()) { + logger.debug("Performing Realm routing. Realm [{}] has the following peers available [{}] from list [{}]", + new Object[] {destRealm, availablePeers, Arrays.asList(peers)}); + } + + // Balancing + IPeer peer = selectPeer(availablePeers, message); + if (peer == null) { + throw new NoMorePeersAvailableException( + "Unable to find a valid connection within realm [" + destRealm + "]"); + } + else { + if (logger.isDebugEnabled()) { + logger.debug("Load balancing selected peer with uri [{}]", peer.getUri()); + } + } + + return peer; + } + } + + private List getPeers(String destRealm, String[] peers, IPeerTable manager, PeerState state) { + List availablePeers = new ArrayList(5); + logger.debug("Looping through peers in realm [{}]", destRealm); + for (String peerName : peers) { + IPeer localPeer = manager.getPeer(peerName); + if (logger.isDebugEnabled()) { + logger.debug("Checking peer [{}] for name [{}]", new Object[]{localPeer, peerName}); + } + + if (localPeer != null && localPeer.getState(PeerState.class) == state) { + if (localPeer.hasValidConnection()) { + if (logger.isDebugEnabled()) { + logger.debug( + "Found available peer to add to available peer list with uri [{}] with a valid connection", + localPeer.getUri().toString()); + } + availablePeers.add(localPeer); + } + else { + if (logger.isDebugEnabled()) { + logger.debug("Found a peer with uri [{}] with no valid connection", localPeer.getUri()); + } + } + } + } + + return availablePeers; + } + + /** + * Applies load balancing algorithm and session persistence thereafter if its enabled. + */ + public IPeer selectPeer(List availablePeers, IMessage message) { + IPeer peer = null; + if (logger.isDebugEnabled()) { + logger.debug(super.dumpRoundRobinContext()); + } + peer = super.selectPeer(availablePeers); + + if (peer == null) { + return null; + } + if (isSessionPersistentRoutingEnabled()) { + String sessionAssignedPeer = sessionDatasource.getSessionPeer(message.getSessionId()); + if (sessionAssignedPeer != null && !peer.getUri().getFQDN().equals(sessionAssignedPeer)) { + if (logger.isDebugEnabled()) { + logger.debug("Peer reselection took place from [{}] to [{}] on session [{}]", new Object[]{sessionAssignedPeer, peer.getUri().getFQDN(), message + .getSessionId()}); + } + sessionDatasource.setSessionPeer(message.getSessionId(), peer); + } + else if (sessionAssignedPeer == null) { + sessionDatasource.setSessionPeer(message.getSessionId(), peer); + if (logger.isDebugEnabled()) { + logger.debug("Peer [{}] selected and assigned to session [{}]", new Object[]{peer.getUri().getFQDN(), message.getSessionId()}); + } + } + + } + + return peer; + } + + /* + * (non-Javadoc) + * @see org.jdiameter.client.impl.router.RouterImpl#isSessionAware() + */ + @Override + public boolean isSessionAware() { + return isSessionPersistentRoutingEnabled(); + } + + /* + * (non-Javadoc) + * @see org.jdiameter.client.impl.router.RouterImpl#getLastSelectedRating() + */ + @Override + protected int getLastSelectedRating() { + return this.lastSelectedRating; + } + + /* + * (non-Javadoc) + * @see org.jdiameter.client.impl.router.RouterImpl#isWrapperFor(java.lang.Class) + */ + @Override + public boolean isWrapperFor(Class aClass) { + if (aClass == IRoutingAwareSessionDatasource.class) { + return isSessionAware(); + } + else { + return super.isWrapperFor(aClass); + } + } + + /* + * (non-Javadoc) + * @see org.jdiameter.client.impl.router.RouterImpl#unwrap(java.lang.Class) + */ + @Override + public T unwrap(Class aClass) { + if (aClass == IRoutingAwareSessionDatasource.class) { + return aClass.cast(sessionDatasource); + } + else { + return super.unwrap(aClass); + } + } + + /*********************************************************************** + * *********************** Local helper methods ************************* + ***********************************************************************/ + + private List narrowToSelectablePeersSubset(List peers, int rating, IMessage message) { + List peersSubset = new ArrayList(5); + String sessionAssignedPeer = sessionDatasource.getSessionPeer(message.getSessionId()); + for (IPeer peer : peers) { + if (isSessionPersistentRoutingEnabled() && sessionAssignedPeer != null) { + if (peer.getUri().getFQDN().equals(sessionAssignedPeer)) { + if (logger.isDebugEnabled()) { + logger.debug("Sticky sessions are enabled and peer [{}] is assigned to the current session [{}]", new Object[]{sessionAssignedPeer, message + .getSessionId()}); + } + peersSubset.clear(); + peersSubset.add(peer); + break; + } + } + if (peer.getRating() == rating) { + peersSubset.add(peer); + } + } + + if (logger.isDebugEnabled() && sessionAssignedPeer == null) { + logger.debug("Sticky sessions are enabled and no peer has been yet assigned to the current session [{}]", message.getSessionId()); + } + + return peersSubset; + } + + private int findMaximumRating(List peers) { + int maxRating = -1; + for (IPeer peer : peers) { + maxRating = Math.max(maxRating, peer.getRating()); + } + return maxRating; + } + + private boolean isSessionPersistentRoutingEnabled() { + return this.sessionDatasource != null; + } +} diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/RouterImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/RouterImpl.java index 09d4cfee1..afd42c7e3 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/RouterImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/RouterImpl.java @@ -83,6 +83,7 @@ import org.jdiameter.api.LocalAction; import org.jdiameter.api.Message; import org.jdiameter.api.MetaData; +import org.jdiameter.api.NoMorePeersAvailableException; import org.jdiameter.api.PeerState; import org.jdiameter.api.RouteException; import org.jdiameter.api.URI; @@ -469,7 +470,8 @@ public IPeer getPeer(IMessage message, IPeerTable manager) throws RouteException // Balancing IPeer peer = selectPeer(availablePeers); if (peer == null) { - throw new RouteException("Unable to find valid connection to peer[" + destHost + "] in realm[" + destRealm + "]"); + throw new NoMorePeersAvailableException( + "Unable to find a valid connection within realm [" + destRealm + "]"); } else { if (logger.isDebugEnabled()) { @@ -481,7 +483,10 @@ public IPeer getPeer(IMessage message, IPeerTable manager) throws RouteException } } - @Override + public boolean isSessionAware() { + return false; + } + public IRealmTable getRealmTable() { return this.realmTable; } @@ -955,4 +960,27 @@ public String toString() { return "AnswerEntry {" + "createTime=" + createTime + ", hopByHopId=" + hopByHopId + '}'; } } + + protected String dumpRoundRobinContext() { + return "Load balancing is not supported"; + } + + protected int getLastSelectedRating() { + return Integer.MIN_VALUE; + } + + @Override + public boolean isWrapperFor(Class aClass) { + return aClass == IRouter.class; + } + + @Override + public T unwrap(Class 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/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..a7cc7e763 --- /dev/null +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java @@ -0,0 +1,165 @@ +/* + * 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; + +import java.io.Serializable; + +import static org.jdiameter.client.impl.helpers.Parameters.SessionInactivityTimeOut; + +/** + * 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 String SESSION_INACTIVITY_TIMER_NAME = "Ro_CLIENT_SESSION_INACTIVITY_TIMER"; + + private static final Logger logger = LoggerFactory.getLogger(AppRoutingAwareSessionImpl.class); + + private transient IPeerTable peerTable = null; + private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null; + + private final int sesInactivityTimerVal; + private Serializable sesInactivityTimerId = 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); + sesInactivityTimerVal = sessionFactory.getContainer().getConfiguration().getIntValue(SessionInactivityTimeOut.ordinal(), (Integer) + SessionInactivityTimeOut.defValue()) * 1000; + if (sessionStorage instanceof IRoutingAwareSessionDatasource) { + sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; + } + } + + /** + * Tells whether session persistent routing is enabled for this session. + * + * @return true if enabled + */ + protected boolean isSessionPersistenceEnabled() { + return this.sessionPersistenceStorage != null; + } + + /** + * 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; + } + } + + /** + * Starts maximum session inactivity timer which defines how much time the persistence record + * should be kept if there is no request sent within a session. + */ + protected void startSessionInactivityTimer() { + logger.debug("Scheduling session inactivity timer equal to [{}] ms", sesInactivityTimerVal); + stopSessionInactivityTimer(); + this.sesInactivityTimerId = this.timerFacility.schedule(this.getSessionId(), SESSION_INACTIVITY_TIMER_NAME, sesInactivityTimerVal); + } + + /** + * Stops session inactivity timer. + */ + protected void stopSessionInactivityTimer() { + if (this.sesInactivityTimerId != null) { + logger.debug("Stopping session inactivity timer [{}]", this.sesInactivityTimerId); + timerFacility.cancel(this.sesInactivityTimerId); + this.sesInactivityTimerId = 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(SESSION_INACTIVITY_TIMER_NAME)) { + //no need to interfere with session state machine (simply remove routing context used for sticky sessions based routing) + String oldPeer = flushSessionPersistenceContext(); + logger.debug("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/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..16d575126 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 @@ -278,7 +278,7 @@ public AppSession getSession(String sessionId, Class aClas ClientCCASessionImpl clientSession = null; IClientCCASessionData data = (IClientCCASessionData) this.sessionDataFactory.getAppSessionData(ClientCCASession.class, sessionId); - clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), sessionFactory, this.getClientSessionListener(), + clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), iss, sessionFactory, this.getClientSessionListener(), this.getClientContextListener(), this.getStateListener()); clientSession.getSessions().get(0).setRequestListener(clientSession); appSession = clientSession; @@ -320,8 +320,8 @@ public AppSession getNewSession(String sessionId, Class 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()); + 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..2c1c89223 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; @@ -39,6 +41,7 @@ import org.jdiameter.api.ro.ServerRoSessionListener; import org.jdiameter.api.ro.events.RoCreditControlAnswer; import org.jdiameter.api.ro.events.RoCreditControlRequest; +import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.ISessionFactory; import org.jdiameter.client.impl.app.ro.ClientRoSessionImpl; import org.jdiameter.client.impl.app.ro.IClientRoSessionData; @@ -61,6 +64,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 +72,7 @@ public class RoSessionFactoryImpl implements IRoSessionFactory, ClientRoSessionL // Message timeout value (in milliseconds) protected int defaultDirectDebitingFailureHandling = 0; protected int defaultCreditControlFailureHandling = 0; + protected int defaultCreditControlSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; // its seconds protected long defaultValidityTime = 60; @@ -270,8 +275,8 @@ public AppSession getNewSession(String sessionId, Class 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 +325,8 @@ public AppSession getSession(String sessionId, Class 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 +377,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(RouteException cause, ClientRoSession session, Message msg, Peer peer) throws InternalException { + + } + // Message Factory Methods -------------------------------------------------- @Override @@ -466,6 +486,11 @@ public int getDefaultCCFHValue() { return defaultCreditControlFailureHandling; } + @Override + public int getDefaultCCSFValue() { + return defaultCreditControlSessionFailover; + } + @Override public int getDefaultDDFHValue() { return defaultDirectDebitingFailureHandling; @@ -498,14 +523,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> appSessionDataFactories = new HashMap, IAppSessionDataFactory>(); - 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/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/cca/ServerCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/cca/ServerCCASessionImpl.java index c3e2cf37e..b08e2641e 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"); } 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..ec2c7b9bb 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"); } 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..43b638f6c 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,15 @@ 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.RetransmissionTimeOut; 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.SessionInactivityTimeOut; 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 +126,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; @@ -385,12 +389,35 @@ else if (nodeName.equals("Dictionary")) { else if (nodeName.equals("RequestTable")) { addRequestTable(RequestTable, c.item(i)); } + else if (nodeName.equals("SessionInactivityTimeOut")) { + add(SessionInactivityTimeOut, getIntValue(c.item(i))); + } + else if (nodeName.equals("TxTimeOut")) { + add(TxTimeOut, getLongValue(c.item(i))); + } + else if (nodeName.equals("RetransmissionTimeOut")) { + add(RetransmissionTimeOut, 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 +480,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 +581,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..0939b5359 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 @@ -215,6 +215,38 @@ + + + Tx timer as described in chapter 13. of RFC 4006 defined in miliseconds. + + + + + + + + Retransmission stop timer which defines how long the stack should carry on with retransmissions in case of delivery failures. + + + + + + + + Comma delimited list of result codes which make an initial request to be retransmitted. + + + + + + + + Session inactivity timeout in seconds used for session persistence. + + + + + 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..ae0cb3640 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 @@ -280,6 +280,38 @@ + + + Tx timer as described in chapter 13. of RFC 4006 defined in miliseconds. + + + + + + + + Retransmission stop timer which defines how long the stack should carry on with retransmissions in case of delivery failures. + + + + + + + + Comma delimited list of result codes which make an initial request to be retransmitted. + + + + + + + + Session inactivity timeout in seconds used for session persistence. + + + + + Server Socket bind delay in milliseconds. 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..de658be55 --- /dev/null +++ b/core/mux/common/config/jdiameter-config_ext_routing_failover.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..fc460b0ba 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,13 @@ 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.RetransmissionTimeOut; +import static org.jdiameter.client.impl.helpers.Parameters.SessionInactivityTimeOut; 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 +107,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 +589,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 +855,31 @@ public void _Parameters_setRecTimeout(long stopTimeout) throws MBeanException { getMutableConfiguration().setLongValue(RecTimeOut.ordinal(), stopTimeout); } + public void _Parameters_setSessionInactivityTimeout(int timeout) throws MBeanException { + getMutableConfiguration().setIntValue(SessionInactivityTimeOut.ordinal(), timeout); + } + + public void _Parameters_setTxTimeout(long txTimeout) throws MBeanException { + getMutableConfiguration().setLongValue(TxTimeOut.ordinal(), txTimeout); + } + + public void _Parameters_setRetransmissionTimeout(long retransmissionTimeout) throws MBeanException { + getMutableConfiguration().setLongValue(RetransmissionTimeOut.ordinal(), retransmissionTimeout); + } + + 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 +1020,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..6bfacc522 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,43 @@ public interface DiameterStackMultiplexerMBean extends ServiceMBean { */ void _Parameters_setRecTimeout(long recTimeout) throws MBeanException; + /** + * Sets the timeout value for session inactivity timer which defines how much time + * the persistence record should be kept if there is no request sent within a session. + * Irrelevant when session persistent routing is not enabled, defaults to 1800 seconds. + * + * @param timeout the amount of time, in seconds. + * @throws MBeanException if the operation is unable to perform correctly + */ + void _Parameters_setSessionInactivityTimeout(int timeout) 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 one of failover algorithm stop conditions. Namely, in case of consecutive peers + * failures the failover algorithm will try to retransmit a given message to other peers + * until retransmission timeout expires + * + * @param retransmissionTimeout the amount of time, in ms. + * @throws MBeanException if the operation is unable to perform correctly + */ + void _Parameters_setRetransmissionTimeout(long retransmissionTimeout) 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 +374,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..9ffd7470e 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,14 @@ public interface Parameters extends Serializable { void setRecTimeout(long recTimeout); + int getSessionInactivityTimeout(); + + void setSessionInactivityTimeout(long sessionInactivityTimeout); + + 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..aceccced1 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,13 @@ 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.RetransmissionTimeOut; +import static org.jdiameter.client.impl.helpers.Parameters.SessionInactivityTimeOut; 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 +67,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 +98,10 @@ public class ParametersImpl implements Parameters { private long dwaTimeout; private long dpaTimeout; private long recTimeout; + private long txTimeout; + private long retransmissionTimeOut; + private String retransmissionRequiredResCodes; + private int sessionInactivityTimeout; // Gone since merge with build-350 // private String threadPool_Priority; @@ -119,6 +128,10 @@ 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.retransmissionTimeOut = config.getLongValue(RetransmissionTimeOut.ordinal(), 45000L); + this.retransmissionRequiredResCodes = Arrays.toString(config.getIntArrayValue(RetransmissionRequiredResCodes.ordinal(), null)); + this.sessionInactivityTimeout = config.getIntValue(SessionInactivityTimeOut.ordinal(), 600); // Concurrent Entities for (Configuration concurrentEntity : config.getChildren(Concurrent.ordinal())) { @@ -253,6 +266,38 @@ public void setRecTimeout(long recTimeout) { DiameterConfiguration.getMutableConfiguration().setLongValue(RecTimeOut.ordinal(), recTimeout); } + public int getSessionInactivityTimeout() { + return sessionInactivityTimeout; + } + + public void setSessionInactivityTimeout(long sessionInactivityTimeout) { + DiameterConfiguration.getMutableConfiguration().setLongValue(SessionInactivityTimeOut.ordinal(), sessionInactivityTimeout); + } + + public long getTxTimeout() { + return txTimeout; + } + + public void setTxTimeout(long txTimeout) { + DiameterConfiguration.getMutableConfiguration().setLongValue(TxTimeOut.ordinal(), txTimeout); + } + + public long getRetransmissionTimeout() { + return retransmissionTimeOut; + } + + public void setRetransmissionTimeout(long retrTimeout) { + DiameterConfiguration.getMutableConfiguration().setLongValue(RetransmissionTimeOut.ordinal(), retrTimeout); + } + + 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} + @@ -141,6 +151,7 @@ + diff --git a/core/mux/sar-jboss-5/pom.xml b/core/mux/sar-jboss-5/pom.xml index 98f159b29..9859a9034 100644 --- a/core/mux/sar-jboss-5/pom.xml +++ b/core/mux/sar-jboss-5/pom.xml @@ -45,6 +45,16 @@ ../common/config false + + jdiameter-config_*.xml + + + + ../common/config + false + + ${jdiameter.mux.config.file} + @@ -141,7 +151,8 @@ - + + diff --git a/core/mux/sar-jboss-7/pom.xml b/core/mux/sar-jboss-7/pom.xml index 3a1c2a541..406562ff1 100644 --- a/core/mux/sar-jboss-7/pom.xml +++ b/core/mux/sar-jboss-7/pom.xml @@ -149,10 +149,13 @@ - + + - + + From 7a2e62b58e087bf37c56a41e7a048c90b0f89ba7 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Mon, 3 Jul 2017 11:12:01 +0200 Subject: [PATCH 02/26] changed RequestType package --- .../src/main/java/org/jdiameter/api/{ => cca}/RequestType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename core/jdiameter/api/src/main/java/org/jdiameter/api/{ => cca}/RequestType.java (95%) diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/RequestType.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/cca/RequestType.java similarity index 95% rename from core/jdiameter/api/src/main/java/org/jdiameter/api/RequestType.java rename to core/jdiameter/api/src/main/java/org/jdiameter/api/cca/RequestType.java index d82affae3..2cdd3c244 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/RequestType.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/cca/RequestType.java @@ -17,7 +17,7 @@ * along with this program. If not, see */ -package org.jdiameter.api; +package org.jdiameter.api.cca; /** * This enumerated class defines CC-Request-Type AVP possible values as described in RFC 4006: From 162287f584edbb37e46b1cd3088c0003024faa9c Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 5 Jul 2017 11:05:25 +0200 Subject: [PATCH 03/26] implemented additional method in testsuite --- .../stack/functional/ro/base/Client.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java b/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java index 66c883fb4..e9e114aa5 100644 --- a/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java +++ b/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java @@ -23,7 +23,9 @@ import org.jdiameter.api.IllegalDiameterStateException; import org.jdiameter.api.InternalException; +import org.jdiameter.api.Message; import org.jdiameter.api.OverloadException; +import org.jdiameter.api.Peer; import org.jdiameter.api.RouteException; import org.jdiameter.api.app.AppAnswerEvent; import org.jdiameter.api.app.AppRequestEvent; @@ -169,6 +171,21 @@ public void doOtherEvent(AppSession session, AppRequestEvent request, AppAnswerE fail("Received \"Other\" event, request[" + request + "], answer[" + answer + "], on session[" + session + "]", null); } + @Override + public void doRequestTxTimeout(ClientRoSession clientRoSession, Message message, Peer peer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + + } + + @Override + public void doRequestTimeout(ClientRoSession clientRoSession, Message message, Peer peer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + + } + + @Override + public void doPeerUnavailability(RouteException e, ClientRoSession clientRoSession, Message message, Peer peer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + + } + // ------------ getters for some vars; public boolean isSentINITIAL() { @@ -215,4 +232,8 @@ protected String getServiceContextId() { return "tralalalal ID"; } + @Override + public int getDefaultCCSFValue() { + return 0; + } } From f31450bd41977c9ac874501354c816c26b884f2b Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Tue, 4 Jul 2017 12:39:01 +0200 Subject: [PATCH 04/26] 1. Added new classes, back to previous versions IMessage and MessageImpl 2. IMessage to ICCAMessage changed in ClientRoSessionImpl --- .../org/jdiameter/client/api/IMessage.java | 50 ------- .../client/api/app/cca/ICCAMessage.java | 78 ++++++++++ .../impl/app/ro/ClientRoSessionImpl.java | 32 ++--- .../client/impl/parser/CCAMessageImpl.java | 136 ++++++++++++++++++ .../client/impl/parser/MessageImpl.java | 41 +----- 5 files changed, 231 insertions(+), 106 deletions(-) create mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java create mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java index dc3663b07..bae98da48 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java @@ -82,16 +82,6 @@ public interface IMessage extends IRequest, IAnswer { */ int STATE_ANSWERED = 3; - /** - * 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; - /** * Return state of message * @@ -193,46 +183,6 @@ public interface IMessage extends IRequest, IAnswer { */ boolean isTimeOut(); - /** - * Tells if there are any timers set to monitor potential retransmissions - * - * @return true if potential retransmissions will be handled - */ - boolean isRetransmissionSupervised(); - - /** - * Marks that message to be under supervision timers guarding retransmissions - * - * @param arg true if supervision is active - */ - void setRetransmissionSupervised(boolean arg); - - /** - * Tells if the number of allowed retransmissions for this message is - * already exceeded or not. - * - * @return false if no more retransmissions are allowed - */ - boolean isRetransmissionAllowed(); - - /** - * @return value of CC-Session-Failover AVP. - */ - int getCcSessionFailover(); - - /** - * Sets the number of allowed retransmissions for this message that can be performed - * in case of failure detection. - * - * @param arg number of allowed retransmissions - */ - void setNumberOfRetransAllowed(int arg); - - /** - * Decrements the number of allowed retransmissions for this message. - */ - void decrementNumberOfRetransAllowed(); - /** * Set event listener * diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java new file mode 100644 index 000000000..4e98eb514 --- /dev/null +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java @@ -0,0 +1,78 @@ + /* + * 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.client.api.app.cca; + + import org.jdiameter.client.api.IMessage; + + /** + * @author Grzegorz Figiel (ProIDS sp. z o.o.) + */ + public interface ICCAMessage extends IMessage { + + /** + * 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; + + /** + * Tells if there are any timers set to monitor potential retransmissions + * + * @return true if potential retransmissions will be handled + */ + boolean isRetransmissionSupervised(); + + /** + * Marks that message to be under supervision timers guarding retransmissions + * + * @param arg true if supervision is active + */ + void setRetransmissionSupervised(boolean arg); + + /** + * Tells if the number of allowed retransmissions for this message is + * already exceeded or not. + * + * @return false if no more retransmissions are allowed + */ + boolean isRetransmissionAllowed(); + + /** + * @return value of CC-Session-Failover AVP. + */ + int getCcSessionFailover(); + + /** + * Sets the number of allowed retransmissions for this message that can be performed + * in case of failure detection. + * + * @param arg number of allowed retransmissions + */ + void setNumberOfRetransAllowed(int arg); + + /** + * Decrements the number of allowed retransmissions for this message. + */ + void decrementNumberOfRetransAllowed(); + } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index e2ea4bacd..1383de5c5 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -74,8 +74,8 @@ import org.jdiameter.api.ro.events.RoCreditControlAnswer; import org.jdiameter.api.ro.events.RoCreditControlRequest; import org.jdiameter.client.api.IContainer; -import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.ISessionFactory; +import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.client.api.parser.ParseException; import org.jdiameter.client.api.router.IRouter; @@ -369,7 +369,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx setState(ClientRoSessionState.PENDING_INITIAL); // RFC 4006: For new credit-control sessions, failover to an alternative // credit-control server SHOULD be performed if possible. - sessionData.setGatheredCCSF(IMessage.SESSION_FAILOVER_SUPPORTED_VALUE); + sessionData.setGatheredCCSF(ICCAMessage.SESSION_FAILOVER_SUPPORTED_VALUE); try { dispatchEvent(localEvent.getRequest()); } @@ -391,7 +391,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx AppAnswerEvent answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_INITIAL_ANSWER: - sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + sessionData.setGatheredCCSF(((ICCAMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_I @@ -540,7 +540,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_UPDATE_ANSWER: - sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + sessionData.setGatheredCCSF(((ICCAMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_U @@ -633,7 +633,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { //FIXME: Alex broke this, setting back "true" ? //setState(ClientRoSessionState.IDLE, false); - sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + sessionData.setGatheredCCSF(((ICCAMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = ((AppAnswerEvent) localEvent.getAnswer()).getResultCodeAvp().getUnsigned32(); if (retrRequiredErrorCodes.contains(resultCode)) { handleRetransmissionDueToError(eventType, localEvent.getRequest().getMessage()); @@ -1321,7 +1321,7 @@ protected void handlePeerUnavailability(Message msg, NoMorePeersAvailableExcepti setState(ClientRoSessionState.IDLE, true); } - protected void handleRetransmission(Type eventType, IMessage msg, boolean tFlagSetting) { + protected void handleRetransmission(Type eventType, ICCAMessage msg, boolean tFlagSetting) { msg.setReTransmitted(tFlagSetting); if (this.sessionData.getRetransmissionTimerId() == null) { startFailoverStopTimer(); @@ -1353,7 +1353,7 @@ protected void handleRetransmission(Type eventType, IMessage msg, boolean tFlagS } protected void handleRetransmissionDueToError(Type eventType, Message msg) { - IMessage imsg = (IMessage) msg; + ICCAMessage imsg = (ICCAMessage) msg; logger.warn("Message will be retransmitted due to error response [{}] ", msg); try { @@ -1379,7 +1379,7 @@ protected void handleRetransmissionDueToError(Type eventType, Message msg) { protected void handleRetransmissionDueToTimeout(Type eventType, AppEvent event) throws InternalException { if (isSessionFailoverSupported()) { - handleRetransmission(eventType, (IMessage) event.getMessage(), true); + handleRetransmission(eventType, (ICCAMessage) event.getMessage(), true); } else { logger.warn("Failed to send message. Failover unsupported for session ID: {}", sessionData.getSessionId()); @@ -1457,7 +1457,7 @@ protected void deliverRequestTxTimeout(Message msg) { logger.debug("Propagating Tx timeout event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { - listener.doRequestTxTimeout(this, msg, ((IMessage) msg).getPeer()); + listener.doRequestTxTimeout(this, msg, ((ICCAMessage) msg).getPeer()); } } catch (Exception e) { @@ -1469,7 +1469,7 @@ protected void deliverRequestTimeout(Message msg) { logger.debug("Propagating timeout event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { - listener.doRequestTimeout(this, msg, ((IMessage) msg).getPeer()); + listener.doRequestTimeout(this, msg, ((ICCAMessage) msg).getPeer()); } } catch (Exception e) { @@ -1481,7 +1481,7 @@ protected void deliverPeerUnavailabilityError(Message msg, NoMorePeersAvailableE logger.debug("Propagating peer unavailability error event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { - listener.doPeerUnavailability(cause, this, msg, ((IMessage) msg).getPeer()); + listener.doPeerUnavailability(cause, this, msg, ((ICCAMessage) msg).getPeer()); } } catch (Exception e) { @@ -1531,7 +1531,7 @@ else if (request != null) { } } - protected void dispatchEvent(IMessage message) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + protected void dispatchEvent(ICCAMessage message) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { if (message.isRequest()) { message.setRetransmissionSupervised(true); } @@ -1539,7 +1539,7 @@ protected void dispatchEvent(IMessage message) throws InternalException, Illegal } protected void dispatchEvent(AppEvent event) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { - dispatchEvent((IMessage) event.getMessage()); + dispatchEvent((ICCAMessage) event.getMessage()); } protected boolean isProvisional(long resultCode) { @@ -1647,7 +1647,7 @@ private Message messageFromBuffer(ByteBuffer request) throws InternalException { return null; } - private ByteBuffer messageToBuffer(IMessage msg) throws InternalException { + private ByteBuffer messageToBuffer(ICCAMessage msg) throws InternalException { try { return parser.encodeMessage(msg); } @@ -1657,9 +1657,9 @@ private ByteBuffer messageToBuffer(IMessage msg) throws InternalException { } private void resetMessageStatus(Message message) { - IMessage msg = (IMessage) message; + ICCAMessage msg = (ICCAMessage) message; msg.clearTimer(); - msg.setState(IMessage.STATE_NOT_SENT); + msg.setState(ICCAMessage.STATE_NOT_SENT); if (msg.getPeer() != null) { msg.getPeer().remMessage(msg); } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java new file mode 100644 index 000000000..047856abb --- /dev/null +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java @@ -0,0 +1,136 @@ + /* + * 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 + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * JBoss, Home of Professional Open Source + * Copyright 2007-2011, Red Hat, Inc. and individual contributors + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.jdiameter.client.impl.parser; + + import org.jdiameter.api.Avp; + import org.jdiameter.api.AvpDataException; + import org.jdiameter.client.api.app.cca.ICCAMessage; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + + + /** + * Represents a Diameter message. + * + * @author erick.svenson@yahoo.com + * @author Alexandre Mendonca + * @author Bartosz Baranowski + * @author Grzegorz Figiel (ProIDS sp. z o.o.) + */ + public class CCAMessageImpl extends MessageImpl implements ICCAMessage { + + private static final Logger logger = LoggerFactory.getLogger(CCAMessageImpl.class); + + boolean isRetransSupervisionActive = false; + int numberOfRetransAllowed = Integer.MIN_VALUE; + + /** + * Create empty message + * + * @param commandCode + * @param appId + */ + CCAMessageImpl(int commandCode, long appId) { + super(commandCode, appId); + } + + /** + * Create empty message + * + * @param commandCode + * @param applicationId + * @param flags + * @param hopByHopId + * @param endToEndId + * @param avpSet + */ + CCAMessageImpl(int commandCode, long applicationId, short flags, long hopByHopId, long endToEndId, AvpSetImpl avpSet) { + super(commandCode, applicationId, flags, hopByHopId, endToEndId, avpSet); + } + + /** + * Create Answer + * + * @param request parent request + */ + private CCAMessageImpl(CCAMessageImpl request) { + super(request); + } + + @Override + public boolean isRetransmissionSupervised() { + return this.isRetransSupervisionActive; + } + + public void setRetransmissionSupervised(boolean arg) { + this.isRetransSupervisionActive = arg; + } + + public boolean isRetransmissionAllowed() { + return this.numberOfRetransAllowed > 0; + } + + public int getCcSessionFailover() { + try { + Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); + if (avpCcSessionFailover != null) { + return avpCcSessionFailover.getInteger32(); + } + } + catch (AvpDataException ade) { + logger.error("Failed to fetch CC-Session-Failover", ade); + } + return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + } + + public void setNumberOfRetransAllowed(int arg) { + if (this.numberOfRetransAllowed < 0) { + this.numberOfRetransAllowed = arg; + } + } + + public void decrementNumberOfRetransAllowed() { + this.numberOfRetransAllowed--; + } + + } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java index 1b8a9368f..4f233d536 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java @@ -69,7 +69,6 @@ * @author erick.svenson@yahoo.com * @author Alexandre Mendonca * @author Bartosz Baranowski - * @author Grzegorz Figiel (ProIDS sp. z o.o.) */ public class MessageImpl implements IMessage { @@ -89,8 +88,6 @@ public class MessageImpl implements IMessage { AvpSetImpl avpSet; boolean isNetworkRequest = false; - boolean isRetransSupervisionActive = false; - int numberOfRetransAllowed = Integer.MIN_VALUE; transient IPeer peer; transient TimerTask timerTask; @@ -158,7 +155,7 @@ public class MessageImpl implements IMessage { * * @param request parent request */ - private MessageImpl(MessageImpl request) { + MessageImpl(MessageImpl request) { this(request.getCommandCode(), request.getHeaderApplicationId()); copyHeader(request); setRequest(false); @@ -267,42 +264,6 @@ public void setReTransmitted(boolean b) { } } - @Override - public boolean isRetransmissionSupervised() { - return this.isRetransSupervisionActive; - } - - public void setRetransmissionSupervised(boolean arg) { - this.isRetransSupervisionActive = arg; - } - - public boolean isRetransmissionAllowed() { - return this.numberOfRetransAllowed > 0; - } - - public int getCcSessionFailover() { - try { - Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); - if (avpCcSessionFailover != null) { - return avpCcSessionFailover.getInteger32(); - } - } - catch (AvpDataException ade) { - logger.error("Failed to fetch CC-Session-Failover", ade); - } - return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; - } - - public void setNumberOfRetransAllowed(int arg) { - if (this.numberOfRetransAllowed < 0) { - this.numberOfRetransAllowed = arg; - } - } - - public void decrementNumberOfRetransAllowed() { - this.numberOfRetransAllowed--; - } - public int getCommandCode() { return this.commandCode; } From 1cedf9ce8fa4ed6a9bec70a777bc5a5d4ef0dbdd Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 5 Jul 2017 09:40:01 +0200 Subject: [PATCH 05/26] Cherry picked commits 1. a719ece98961fbe2df246d126ffeea6eae1d8c6d 2. faeb9de01db8afed0adf366a1ff926c102ab6fc3 3. 2fbe2da2045947bd8e5a637e418e9d9c0cd502d9 4. b672ed25031b1ab84195412d86380f61941ca5d1 --- .../ha/timer/ReplicatedTimerFacilityImpl.java | 19 +- .../java/org/jdiameter/api/BaseSession.java | 2 + .../client/impl/BaseSessionImpl.java | 43 +++- .../jdiameter/client/impl/RawSessionImpl.java | 6 +- .../jdiameter/client/impl/SessionImpl.java | 10 +- .../impl/app/acc/ClientAccSessionImpl.java | 7 +- .../impl/app/auth/ClientAuthSessionImpl.java | 8 +- .../impl/app/cca/ClientCCASessionImpl.java | 5 +- .../impl/app/cxdx/CxDxClientSessionImpl.java | 8 +- .../impl/app/gq/GqClientSessionImpl.java | 8 +- .../impl/app/gx/ClientGxSessionImpl.java | 8 +- .../impl/app/rf/ClientRfSessionImpl.java | 8 +- .../impl/app/rx/ClientRxSessionImpl.java | 6 + .../impl/app/s13/S13ClientSessionImpl.java | 8 +- .../impl/app/s6a/S6aClientSessionImpl.java | 8 +- .../impl/app/sh/ShClientSessionImpl.java | 7 +- .../client/impl/helpers/Parameters.java | 4 + .../common/impl/app/AppSessionImpl.java | 13 + .../impl/timer/LocalTimerFacilityImpl.java | 16 +- .../impl/app/acc/ServerAccSessionImpl.java | 7 +- .../impl/app/auth/ServerAuthSessionImpl.java | 8 +- .../impl/app/cca/ServerCCASessionImpl.java | 8 +- .../impl/app/cxdx/CxDxServerSessionImpl.java | 8 +- .../impl/app/gq/GqServerSessionImpl.java | 8 +- .../impl/app/gx/ServerGxSessionImpl.java | 8 +- .../impl/app/rf/ServerRfSessionImpl.java | 8 +- .../impl/app/ro/ServerRoSessionImpl.java | 8 +- .../impl/app/rx/ServerRxSessionImpl.java | 6 + .../impl/app/s13/S13ServerSessionImpl.java | 8 +- .../impl/app/s6a/S6aServerSessionImpl.java | 8 +- .../impl/app/sh/ShServerSessionImpl.java | 7 +- .../server/impl/helpers/XMLConfiguration.java | 4 + .../resources/META-INF/jdiameter-client.xsd | 8 + .../resources/META-INF/jdiameter-server.xsd | 8 + .../ro/base/RoSessionBasicFlowIdleTest.java | 238 ++++++++++++++++++ .../config-server-node1-session-idle.xml | 58 +++++ 36 files changed, 563 insertions(+), 39 deletions(-) create mode 100644 testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/RoSessionBasicFlowIdleTest.java create mode 100644 testsuite/tests/src/test/resources/configurations/functional-ro/config-server-node1-session-idle.xml diff --git a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/timer/ReplicatedTimerFacilityImpl.java b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/timer/ReplicatedTimerFacilityImpl.java index 9f4a92242..50972b201 100644 --- a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/timer/ReplicatedTimerFacilityImpl.java +++ b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/timer/ReplicatedTimerFacilityImpl.java @@ -46,6 +46,7 @@ import org.jdiameter.api.BaseSession; import org.jdiameter.client.api.IContainer; +import org.jdiameter.client.impl.BaseSessionImpl; import org.jdiameter.common.api.data.ISessionDatasource; import org.jdiameter.common.api.timer.ITimerFacility; import org.jdiameter.common.impl.app.AppSessionImpl; @@ -129,13 +130,25 @@ public void runTask() { try { DiameterTimerTaskData data = (DiameterTimerTaskData) getData(); BaseSession bSession = sessionDataSource.getSession(data.getSessionId()); - if (bSession == null || !bSession.isAppSession()) { + if (bSession == null) { // FIXME: error ? + logger.error("Base Session is null for sessionId: {}", data.getSessionId()); return; } else { - AppSessionImpl impl = (AppSessionImpl) bSession; - impl.onTimer(data.getTimerName()); + try { + if (!bSession.isAppSession()) { + BaseSessionImpl impl = (BaseSessionImpl) bSession; + impl.onTimer(data.getTimerName()); + } + else { + AppSessionImpl impl = (AppSessionImpl) bSession; + impl.onTimer(data.getTimerName()); + } + } + catch (Exception e) { + logger.error("Caught exception from session object!", e); + } } } catch (Exception e) { diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java index e724e7b07..572222746 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java @@ -104,4 +104,6 @@ public interface BaseSession { * @return session-id as String (Session-Id AVP) */ String getSessionId(); + + String IDLE_SESSION_TIMER_NAME = "IDLE_SESSION_TIMER"; } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java index cf81b8fb3..da588a943 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java @@ -43,7 +43,9 @@ package org.jdiameter.client.impl; import static org.jdiameter.client.impl.helpers.Parameters.MessageTimeOut; +import static org.jdiameter.client.impl.helpers.Parameters.SessionTimeOut; +import java.io.Serializable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -65,10 +67,14 @@ import org.jdiameter.api.OverloadException; import org.jdiameter.api.Request; import org.jdiameter.api.RouteException; +import org.jdiameter.client.api.IAssembler; import org.jdiameter.client.api.IContainer; import org.jdiameter.client.api.IEventListener; import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.parser.IMessageParser; +import org.jdiameter.common.api.timer.ITimerFacility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Implementation for {@link BaseSession}. @@ -79,15 +85,21 @@ */ public abstract class BaseSessionImpl implements BaseSession { + private static final Logger logger = LoggerFactory.getLogger(BaseSessionImpl.class); + protected final long creationTime = System.currentTimeMillis(); protected long lastAccessedTime = creationTime; protected boolean isValid = true; protected String sessionId; + protected long maxIdleTime = 0; + protected transient IContainer container; protected transient IMessageParser parser; protected NetworkReqListener reqListener; + protected Serializable istTimerId; + @Override public long getCreationTime() { return creationTime; @@ -98,6 +110,31 @@ public long getLastAccessedTime() { return lastAccessedTime; } + protected long setLastAccessTime() { + lastAccessedTime = System.currentTimeMillis(); + if (sessionId != null) { + maxIdleTime = container.getConfiguration().getLongValue(SessionTimeOut.ordinal(), (Long) SessionTimeOut.defValue()); + if (maxIdleTime > 0) { + IAssembler assembler = container.getAssemblerFacility(); + ITimerFacility timerFacility = assembler.getComponentInstance(ITimerFacility.class); + if (istTimerId != null) { + timerFacility.cancel(istTimerId); + } + istTimerId = timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, maxIdleTime); + } + } + return lastAccessedTime; + } + + public void onTimer(String timerName) { + if (timerName.equals(IDLE_SESSION_TIMER_NAME)) { + if (!isValid() || (maxIdleTime > 0 && System.currentTimeMillis() - getLastAccessedTime() >= maxIdleTime)) { + logger.debug("Terminating idle/invalid application session [{}] with SID[{}]", this, getSessionId()); + this.release(); + } + } + } + @Override public boolean isValid() { return isValid; @@ -138,7 +175,7 @@ protected void genericSend(Message message, EventListener listener) protected void genericSend(Message aMessage, EventListener listener, long timeout, TimeUnit timeUnit) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { if (isValid) { - lastAccessedTime = System.currentTimeMillis(); + setLastAccessTime(); IMessage message = (IMessage) aMessage; IEventListener localListener = createListenerWrapper(listener); @@ -402,7 +439,7 @@ public boolean isValid() { @SuppressWarnings("unchecked") public void receivedSuccessMessage(Request request, Answer answer) { if (isValid) { - session.lastAccessedTime = System.currentTimeMillis(); + session.setLastAccessTime(); listener.receivedSuccessMessage(request, answer); } } @@ -411,7 +448,7 @@ public void receivedSuccessMessage(Request request, Answer answer) { @SuppressWarnings("unchecked") public void timeoutExpired(Request message) { if (isValid) { - session.lastAccessedTime = System.currentTimeMillis(); + session.setLastAccessTime(); listener.timeoutExpired(message); } } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/RawSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/RawSessionImpl.java index 6c0c272c2..1b9d34cf9 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/RawSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/RawSessionImpl.java @@ -75,7 +75,7 @@ public class RawSessionImpl extends BaseSessionImpl implements RawSession { @Override public Message createMessage(int commandCode, ApplicationId appId, Avp... avps) { if ( isValid ) { - lastAccessedTime = System.currentTimeMillis(); + setLastAccessTime(); IMessage m = parser.createEmptyMessage(commandCode, getAppId(appId)); m.getAvps().addAvp(avps); appendAppId(appId, m); @@ -88,7 +88,7 @@ public Message createMessage(int commandCode, ApplicationId appId, Avp... avps) @Override public Message createMessage(int commandCode, ApplicationId appId, long hopByHopIdentifier, long endToEndIdentifier, Avp... avps) { if ( isValid ) { - lastAccessedTime = System.currentTimeMillis(); + setLastAccessTime(); IMessage m = parser.createEmptyMessage(commandCode, getAppId(appId)); if (hopByHopIdentifier >= 0) { m.setHopByHopIdentifier(-hopByHopIdentifier); @@ -107,7 +107,7 @@ public Message createMessage(int commandCode, ApplicationId appId, long hopByHop @Override public Message createMessage(Message message, boolean copyAvps) { if ( isValid ) { - lastAccessedTime = System.currentTimeMillis(); + setLastAccessTime(); IMessage newMessage = null; IMessage inner = (IMessage) message; if (copyAvps) { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionImpl.java index 4d6dcbae0..8dbead2c0 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionImpl.java @@ -62,6 +62,7 @@ import org.jdiameter.client.api.ISession; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.common.api.data.ISessionDatasource; +import org.jdiameter.common.api.timer.ITimerFacility; /** * Implementation for {@link ISession} @@ -115,7 +116,7 @@ public NetworkReqListener getReqListener() { @Override public Request createRequest(int commandCode, ApplicationId appId, String destRealm) { if (isValid) { - lastAccessedTime = System.currentTimeMillis(); + setLastAccessTime(); IRequest m = parser.createEmptyMessage(IRequest.class, commandCode, getAppId(appId)); m.setNetworkRequest(false); m.setRequest(true); @@ -135,7 +136,7 @@ public Request createRequest(int commandCode, ApplicationId appId, String destRe @Override public Request createRequest(int commandCode, ApplicationId appId, String destRealm, String destHost) { if (isValid) { - lastAccessedTime = System.currentTimeMillis(); + setLastAccessTime(); IRequest m = parser.createEmptyMessage(IRequest.class, commandCode, getAppId(appId)); m.setNetworkRequest(false); m.setRequest(true); @@ -158,7 +159,7 @@ public Request createRequest(int commandCode, ApplicationId appId, String destRe @Override public Request createRequest(Request prevRequest) { if (isValid) { - lastAccessedTime = System.currentTimeMillis(); + setLastAccessTime(); IRequest request = parser.createEmptyMessage(Request.class, (IMessage) prevRequest); request.setRequest(true); request.setNetworkRequest(false); @@ -174,6 +175,9 @@ public Request createRequest(Request prevRequest) { public void release() { isValid = false; if (container != null) { + if (istTimerId != null) { + container.getAssemblerFacility().getComponentInstance(ITimerFacility.class).cancel(istTimerId); + } container.removeSessionListener(sessionId); // FIXME container.getAssemblerFacility().getComponentInstance(ISessionDatasource.class).removeSession(sessionId); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/acc/ClientAccSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/acc/ClientAccSessionImpl.java index 19f1b9c7e..5708ce78a 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/acc/ClientAccSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/acc/ClientAccSessionImpl.java @@ -622,7 +622,10 @@ protected void processInterimIntervalAvp(StateEvent event) throws InternalExcept */ @Override public void onTimer(String timerName) { - if (timerName.equals(TIMER_NAME_INTERIM)) { + if (timerName.equals(IDLE_SESSION_TIMER_NAME)) { + checkIdleAppSession(); + } + else if (timerName.equals(TIMER_NAME_INTERIM)) { if (context != null) { try { Request interimRecord = createInterimRecord(); @@ -641,7 +644,7 @@ public void onTimer(String timerName) { } } else { - //....? + logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId()); } } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/auth/ClientAuthSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/auth/ClientAuthSessionImpl.java index 9c118bbc4..3564e753b 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/auth/ClientAuthSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/auth/ClientAuthSessionImpl.java @@ -594,7 +594,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); @@ -611,6 +614,9 @@ public void onTimer(String timerName) { sendAndStateLock.unlock(); } } + else { + logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId()); + } } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java index 888135961..1dc496684 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java @@ -638,7 +638,10 @@ protected void stopTx() { */ @Override public void onTimer(String timerName) { - if (timerName.equals(TX_TIMER_NAME)) { + if (timerName.equals(IDLE_SESSION_TIMER_NAME)) { + checkIdleAppSession(); + } + else if (timerName.equals(TX_TIMER_NAME)) { new TxTimerTask(this, this.sessionData.getTxTimerRequest()).run(); } else { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cxdx/CxDxClientSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cxdx/CxDxClientSessionImpl.java index b7226ee1f..a9b2ea28e 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cxdx/CxDxClientSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cxdx/CxDxClientSessionImpl.java @@ -369,7 +369,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 { @@ -385,6 +388,9 @@ public void onTimer(String timerName) { sendAndStateLock.unlock(); } } + else { + logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId()); + } } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gq/GqClientSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gq/GqClientSessionImpl.java index 02f365002..04443f1c3 100755 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gq/GqClientSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gq/GqClientSessionImpl.java @@ -562,7 +562,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); @@ -579,6 +582,9 @@ public void onTimer(String timerName) { sendAndStateLock.unlock(); } } + else { + logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId()); + } } protected AbortSessionAnswer createAbortSessionAnswer(Answer answer) { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gx/ClientGxSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gx/ClientGxSessionImpl.java index c492e970c..028a7fb38 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gx/ClientGxSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/gx/ClientGxSessionImpl.java @@ -611,9 +611,15 @@ protected void stopTx() { */ @Override public void onTimer(String timerName) { - if (timerName.equals(TX_TIMER_NAME)) { + if (timerName.equals(IDLE_SESSION_TIMER_NAME)) { + checkIdleAppSession(); + } + else if (timerName.equals(TX_TIMER_NAME)) { new TxTimerTask(this, this.sessionData.getTxTimerRequest()).run(); } + else { + logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId()); + } } protected void setState(ClientGxSessionState newState) { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rf/ClientRfSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rf/ClientRfSessionImpl.java index 04aec79b0..c156e8dd9 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rf/ClientRfSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rf/ClientRfSessionImpl.java @@ -608,7 +608,10 @@ protected void processInterimIntervalAvp(StateEvent event) throws InternalExcept */ @Override public void onTimer(String timerName) { - if (timerName.equals(TIMER_NAME_INTERIM)) { + if (timerName.equals(IDLE_SESSION_TIMER_NAME)) { + checkIdleAppSession(); + } + else if (timerName.equals(TIMER_NAME_INTERIM)) { if (context != null) { try { Request interimRecord = createInterimRecord(); @@ -626,6 +629,9 @@ public void onTimer(String timerName) { } } } + else { + logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId()); + } } private void startInterimTimer(long v) { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rx/ClientRxSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rx/ClientRxSessionImpl.java index b8c4335ab..97df5be28 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rx/ClientRxSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/rx/ClientRxSessionImpl.java @@ -890,5 +890,11 @@ else if (!sessionData.getClientRxSessionState().equals(other.sessionData.getClie @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()); + } } } \ No newline at end of file diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/s13/S13ClientSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/s13/S13ClientSessionImpl.java index 5bbb6f85a..68a61a932 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/s13/S13ClientSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/s13/S13ClientSessionImpl.java @@ -209,7 +209,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 { @@ -223,6 +226,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/client/impl/app/s6a/S6aClientSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/s6a/S6aClientSessionImpl.java index 5e16dd246..a9aa8fc06 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/s6a/S6aClientSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/s6a/S6aClientSessionImpl.java @@ -371,7 +371,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 { @@ -387,6 +390,9 @@ public void onTimer(String timerName) { sendAndStateLock.unlock(); } } + else { + logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId()); + } } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/sh/ShClientSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/sh/ShClientSessionImpl.java index aa7d00c37..ca275c166 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/sh/ShClientSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/sh/ShClientSessionImpl.java @@ -291,7 +291,12 @@ public boolean isReplicable() { @Override public void onTimer(String timerName) { - // TODO ... + 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/client/impl/helpers/Parameters.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java index c07c3b0fa..c1a654064 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java @@ -123,6 +123,10 @@ public class Parameters extends Ordinal { * Reconnect time out property */ public static final Parameters RecTimeOut = new Parameters("RecTimeOut", Long.class, 10000L); + /** + * Idle session time out property + */ + public static final Parameters SessionTimeOut = new Parameters("SessionTimeOut", Long.class, 0L); /** * Peer FSM Thread Count property 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/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/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 b08e2641e..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 @@ -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 ec2c7b9bb..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 @@ -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/XMLConfiguration.java b/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/helpers/XMLConfiguration.java index 43b638f6c..844646232 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 @@ -112,6 +112,7 @@ 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.SessionInactivityTimeOut; +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; @@ -368,6 +369,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))); } 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 0939b5359..ed1106de7 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. 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 ae0cb3640..0b52a0af8 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 @@ -232,6 +232,14 @@ + + + Session idle time out in milliseconds. + + + + + Default stop time out in milliseconds. diff --git a/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/RoSessionBasicFlowIdleTest.java b/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/RoSessionBasicFlowIdleTest.java new file mode 100644 index 000000000..5ece58381 --- /dev/null +++ b/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/RoSessionBasicFlowIdleTest.java @@ -0,0 +1,238 @@ +/* + * TeleStax, Open Source Cloud Communications + * Copyright 2011-2017, 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.mobicents.diameter.stack.functional.ro.base; + +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileInputStream; +import java.net.URI; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.jdiameter.api.DisconnectCause; +import org.jdiameter.api.Mode; +import org.jdiameter.api.Peer; +import org.jdiameter.api.PeerState; +import org.jdiameter.api.PeerTable; +import org.jdiameter.api.Stack; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** + * + * @author Alexandre Mendonca + * @author Bartosz Baranowski + */ +@RunWith(Parameterized.class) +public class RoSessionBasicFlowIdleTest { + + private Client clientNode; + private Server serverNode1; + private URI clientConfigURI; + private URI serverNode1ConfigURI; + + /** + * @param clientNode + * @param node1 + * @param node2 + * @param serverCount + */ + public RoSessionBasicFlowIdleTest(String clientConfigUrl, String serverNode1ConfigURL) throws Exception { + super(); + this.clientConfigURI = new URI(clientConfigUrl); + this.serverNode1ConfigURI = new URI(serverNode1ConfigURL); + } + + @Before + public void setUp() throws Exception { + try { + this.clientNode = new Client(); + this.serverNode1 = new Server(); + + this.serverNode1.init(new FileInputStream(new File(this.serverNode1ConfigURI)), "SERVER1"); + this.serverNode1.start(); + + this.clientNode.init(new FileInputStream(new File(this.clientConfigURI)), "CLIENT"); + this.clientNode.start(Mode.ANY_PEER, 10, TimeUnit.SECONDS); + Stack stack = this.clientNode.getStack(); + List peers = stack.unwrap(PeerTable.class).getPeerTable(); + if (peers.size() == 1) { + // ok + } + else if (peers.size() > 1) { + // works better with replicated, since disconnected peers are also listed + boolean foundConnected = false; + for (Peer p : peers) { + if (p.getState(PeerState.class).equals(PeerState.OKAY)) { + if (foundConnected) { + throw new Exception("Wrong number of connected peers: " + peers); + } + foundConnected = true; + } + } + } + else { + throw new Exception("Wrong number of connected peers: " + peers); + } + } + catch (Throwable e) { + e.printStackTrace(); + } + } + + @After + public void tearDown() { + if (this.serverNode1 != null) { + try { + this.serverNode1.stop(DisconnectCause.REBOOTING); + } + catch (Exception e) { + + } + this.serverNode1 = null; + } + + if (this.clientNode != null) { + try { + this.clientNode.stop(DisconnectCause.REBOOTING); + } + catch (Exception e) { + + } + this.clientNode = null; + } + } + + @Test + public void testBasicFlow() throws Exception { + try { + // pain of parameter tests :) ? + clientNode.sendInitial(); + waitForMessage(); + + serverNode1.sendInitial(); + waitForMessage(); + + clientNode.sendInterim(); + waitForMessage(); + + serverNode1.sendInterim(); + waitForMessage(5500); // we wait a bit more so session expires with idle + + clientNode.sendTermination(); + waitForMessage(); + + serverNode1.sendTermination(); + waitForMessage(); + } + catch (Exception e) { + // in case the session expired even before receiving the termination + if (!"Request: null".equals(e.getMessage())) { + e.printStackTrace(); + fail(e.toString()); + } + } + + if (!clientNode.isReceiveINITIAL()) { + StringBuilder sb = new StringBuilder("Did not receive INITIAL! "); + sb.append("Client ER:\n").append(clientNode.createErrorReport(this.clientNode.getErrors())); + + fail(sb.toString()); + } + if (!clientNode.isReceiveINTERIM()) { + StringBuilder sb = new StringBuilder("Did not receive INTERIM! "); + sb.append("Client ER:\n").append(clientNode.createErrorReport(this.clientNode.getErrors())); + + fail(sb.toString()); + } + if (!clientNode.isReceiveTERMINATE()) { + // we don't fail here, we wanted session to be terminated when server tries to receive/send TERMINATE + } + if (clientNode.isReceiveTERMINATE()) { + StringBuilder sb = new StringBuilder("Did receive TERMINATE, should not, session should have been terminated by idle! "); + sb.append("Client ER:\n").append(clientNode.createErrorReport(this.clientNode.getErrors())); + + fail(sb.toString()); + } + if (!clientNode.isPassed()) { + StringBuilder sb = new StringBuilder(); + sb.append("Client ER:\n").append(clientNode.createErrorReport(this.clientNode.getErrors())); + + fail(sb.toString()); + } + + if (!serverNode1.isReceiveINITIAL()) { + StringBuilder sb = new StringBuilder("Did not receive INITIAL! "); + sb.append("Server ER:\n").append(serverNode1.createErrorReport(this.serverNode1.getErrors())); + + fail(sb.toString()); + } + else if (!serverNode1.isReceiveINTERIM()) { + StringBuilder sb = new StringBuilder("Did not receive INTERIM! "); + sb.append("Server ER:\n").append(serverNode1.createErrorReport(this.serverNode1.getErrors())); + + fail(sb.toString()); + } + else if (!serverNode1.isReceiveTERMINATE()) { + // we don't fail here, we wanted session to be terminated when server tries to receive/send TERMINATE + } + if (!serverNode1.isPassed()) { + // we don't fail here, we wanted session to be terminated when server tries to receive/send TERMINATE + } + } + + @Parameters + public static Collection data() { + String client = "configurations/functional-ro/config-client.xml"; + String server1 = "configurations/functional-ro/config-server-node1-session-idle.xml"; + + String replicatedClient = "configurations/functional-ro/replicated-config-client.xml"; + String replicatedServer1 = "configurations/functional-ro/replicated-config-server-node1.xml"; + + Class t = RoSessionBasicFlowIdleTest.class; + client = t.getClassLoader().getResource(client).toString(); + server1 = t.getClassLoader().getResource(server1).toString(); + replicatedClient = t.getClassLoader().getResource(replicatedClient).toString(); + replicatedServer1 = t.getClassLoader().getResource(replicatedServer1).toString(); + + return Arrays.asList(new Object[][] { { client, server1 }/*, { replicatedClient, replicatedServer1 }*/ }); + } + + private void waitForMessage(long time) { + try { + Thread.sleep(time); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void waitForMessage() { + waitForMessage(2000); + } + +} diff --git a/testsuite/tests/src/test/resources/configurations/functional-ro/config-server-node1-session-idle.xml b/testsuite/tests/src/test/resources/configurations/functional-ro/config-server-node1-session-idle.xml new file mode 100644 index 000000000..a414482eb --- /dev/null +++ b/testsuite/tests/src/test/resources/configurations/functional-ro/config-server-node1-session-idle.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5c8481c7b91301587401c06288285506b66958a7 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 5 Jul 2017 11:01:46 +0200 Subject: [PATCH 06/26] 1. replaced SESSION_INACTIVITY_TIMER_NAME with IDLE_SESSION_TIME_NAME 2. replaced SessionInactivityTimeout with SessionTimeout --- .../client/impl/app/cca/ClientCCASessionImpl.java | 5 +---- .../common/impl/app/AppRoutingAwareSessionImpl.java | 13 ++++++------- .../common/impl/app/ro/RoSessionFactoryImpl.java | 4 ++-- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java index 1dc496684..888135961 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java @@ -638,10 +638,7 @@ protected void stopTx() { */ @Override public void onTimer(String timerName) { - if (timerName.equals(IDLE_SESSION_TIMER_NAME)) { - checkIdleAppSession(); - } - else if (timerName.equals(TX_TIMER_NAME)) { + if (timerName.equals(TX_TIMER_NAME)) { new TxTimerTask(this, this.sessionData.getTxTimerRequest()).run(); } else { 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 index a7cc7e763..e270eab11 100644 --- 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 @@ -32,7 +32,7 @@ import java.io.Serializable; -import static org.jdiameter.client.impl.helpers.Parameters.SessionInactivityTimeOut; +import static org.jdiameter.client.impl.helpers.Parameters.SessionTimeOut; /** * Routing aware extension of {@link AppSessionImpl} that enables proper diameter session @@ -41,8 +41,6 @@ */ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { - private static final String SESSION_INACTIVITY_TIMER_NAME = "Ro_CLIENT_SESSION_INACTIVITY_TIMER"; - private static final Logger logger = LoggerFactory.getLogger(AppRoutingAwareSessionImpl.class); private transient IPeerTable peerTable = null; @@ -62,8 +60,8 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); - sesInactivityTimerVal = sessionFactory.getContainer().getConfiguration().getIntValue(SessionInactivityTimeOut.ordinal(), (Integer) - SessionInactivityTimeOut.defValue()) * 1000; + sesInactivityTimerVal = sessionFactory.getContainer().getConfiguration().getIntValue(SessionTimeOut.ordinal(), (Integer) + SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; } @@ -134,7 +132,7 @@ protected String flushSessionPersistenceContext() { protected void startSessionInactivityTimer() { logger.debug("Scheduling session inactivity timer equal to [{}] ms", sesInactivityTimerVal); stopSessionInactivityTimer(); - this.sesInactivityTimerId = this.timerFacility.schedule(this.getSessionId(), SESSION_INACTIVITY_TIMER_NAME, sesInactivityTimerVal); + this.sesInactivityTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, sesInactivityTimerVal); } /** @@ -156,7 +154,8 @@ protected void stopSessionInactivityTimer() { */ @Override public void onTimer(String timerName) { - if (timerName.equals(SESSION_INACTIVITY_TIMER_NAME)) { + 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("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/ro/RoSessionFactoryImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/RoSessionFactoryImpl.java index 2c1c89223..580dc4978 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 @@ -41,8 +41,8 @@ import org.jdiameter.api.ro.ServerRoSessionListener; import org.jdiameter.api.ro.events.RoCreditControlAnswer; import org.jdiameter.api.ro.events.RoCreditControlRequest; -import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.ISessionFactory; +import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.impl.app.ro.ClientRoSessionImpl; import org.jdiameter.client.impl.app.ro.IClientRoSessionData; import org.jdiameter.common.api.app.IAppSessionDataFactory; @@ -72,7 +72,7 @@ public class RoSessionFactoryImpl implements IRoSessionFactory, ClientRoSessionL // Message timeout value (in milliseconds) protected int defaultDirectDebitingFailureHandling = 0; protected int defaultCreditControlFailureHandling = 0; - protected int defaultCreditControlSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + protected int defaultCreditControlSessionFailover = ICCAMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; // its seconds protected long defaultValidityTime = 60; From 5f41df6e02b0179305fdfd45a2366426d6dfb87f Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 5 Jul 2017 11:01:58 +0200 Subject: [PATCH 07/26] replaced RetransmissionTimeout with MessageTimeout --- .../jdiameter/client/impl/app/ro/ClientRoSessionImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 1383de5c5..a0be3d1a5 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -93,7 +93,7 @@ import org.slf4j.LoggerFactory; import static org.jdiameter.client.impl.helpers.Parameters.RetransmissionRequiredResCodes; -import static org.jdiameter.client.impl.helpers.Parameters.RetransmissionTimeOut; +import static org.jdiameter.client.impl.helpers.Parameters.MessageTimeOut; import static org.jdiameter.client.impl.helpers.Parameters.TxTimeOut; /** @@ -191,7 +191,7 @@ public ClientRoSessionImpl(IClientRoSessionData sessionData, IRoMessageFactory f this.parser = icontainer.getAssemblerFacility().getComponentInstance(IMessageParser.class); this.router = icontainer.getAssemblerFacility().getComponentInstance(IRouter.class); this.txTimerVal = icontainer.getConfiguration().getLongValue(TxTimeOut.ordinal(), (Long) TxTimeOut.defValue()); - this.retransmissionTimerVal = icontainer.getConfiguration().getLongValue(RetransmissionTimeOut.ordinal(), (Long) RetransmissionTimeOut.defValue()); + this.retransmissionTimerVal = icontainer.getConfiguration().getLongValue(MessageTimeOut.ordinal(), (Long) MessageTimeOut.defValue()); Set tmpErrCodes = new HashSet<>(); for (int val : icontainer.getConfiguration().getIntArrayValue(RetransmissionRequiredResCodes.ordinal(), new int[0])) { @@ -746,7 +746,7 @@ protected void startFailoverStopTimer() { long timerVal = this.retransmissionTimerVal - this.txTimerVal; if (timerVal <= 0) { logger.warn("Value of Tx timer cannot exceed failover stop timer: [{}] vs. [{}] (taking default values)", this.txTimerVal, this.retransmissionTimerVal); - timerVal = this.txTimerVal + (((Long) RetransmissionTimeOut.defValue()) - ((Long) TxTimeOut.defValue())); + timerVal = this.txTimerVal + (((Long) MessageTimeOut.defValue()) - ((Long) TxTimeOut.defValue())); } logger.debug("Scheduling failover stop timer in [{}] ms", timerVal); stopFailoverStopTimer(); From 809679ff7832d4b32c83ad53f88bd23ce2edc7ef Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 5 Jul 2017 11:12:05 +0200 Subject: [PATCH 08/26] jdiameter-config_ext_routing_failover fixed --- core/mux/common/config/jdiameter-config.xml | 1 + .../jdiameter-config_ext_routing_failover.xml | 79 ++++++++++++++++--- 2 files changed, 69 insertions(+), 11 deletions(-) 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_ext_routing_failover.xml b/core/mux/common/config/jdiameter-config_ext_routing_failover.xml index de658be55..18851ea6d 100644 --- a/core/mux/common/config/jdiameter-config_ext_routing_failover.xml +++ b/core/mux/common/config/jdiameter-config_ext_routing_failover.xml @@ -3,10 +3,12 @@ + + @@ -26,7 +28,7 @@ - + @@ -35,15 +37,16 @@ - - - - + + + + + - + @@ -54,17 +57,33 @@ - - + + + + + + + + + + + + + + + + + + - + @@ -72,8 +91,35 @@ - + + + + + + + + + + + + + + + + @@ -82,7 +128,7 @@ - + @@ -91,12 +137,23 @@ + + + + From 4700b9e54e127ca3270ef153fc1ed58cf5533373 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 5 Jul 2017 13:24:22 +0200 Subject: [PATCH 09/26] reformat code --- .../client/api/app/cca/ICCAMessage.java | 132 ++++----- .../client/impl/parser/CCAMessageImpl.java | 266 +++++++++--------- 2 files changed, 199 insertions(+), 199 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java index 4e98eb514..12ee3bbcb 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java @@ -1,78 +1,78 @@ - /* - * 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 - */ +/* +* 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.client.api.app.cca; - import org.jdiameter.client.api.IMessage; +import org.jdiameter.client.api.IMessage; - /** - * @author Grzegorz Figiel (ProIDS sp. z o.o.) - */ - public interface ICCAMessage extends IMessage { +/** + * @author Grzegorz Figiel (ProIDS sp. z o.o.) + */ +public interface ICCAMessage extends IMessage { - /** - * Default CC-Session-Failover AVP value - NOT_SUPPORTED(0) according to RFC 4006. - */ - int SESSION_FAILOVER_NOT_SUPPORTED_VALUE = 0; + /** + * 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; + /** + * CC-Session-Failover AVP value - SUPPORTED(1) according to RFC 4006. + */ + int SESSION_FAILOVER_SUPPORTED_VALUE = 1; - /** - * Tells if there are any timers set to monitor potential retransmissions - * - * @return true if potential retransmissions will be handled - */ - boolean isRetransmissionSupervised(); + /** + * Tells if there are any timers set to monitor potential retransmissions + * + * @return true if potential retransmissions will be handled + */ + boolean isRetransmissionSupervised(); - /** - * Marks that message to be under supervision timers guarding retransmissions - * - * @param arg true if supervision is active - */ - void setRetransmissionSupervised(boolean arg); + /** + * Marks that message to be under supervision timers guarding retransmissions + * + * @param arg true if supervision is active + */ + void setRetransmissionSupervised(boolean arg); - /** - * Tells if the number of allowed retransmissions for this message is - * already exceeded or not. - * - * @return false if no more retransmissions are allowed - */ - boolean isRetransmissionAllowed(); + /** + * Tells if the number of allowed retransmissions for this message is + * already exceeded or not. + * + * @return false if no more retransmissions are allowed + */ + boolean isRetransmissionAllowed(); - /** - * @return value of CC-Session-Failover AVP. - */ - int getCcSessionFailover(); + /** + * @return value of CC-Session-Failover AVP. + */ + int getCcSessionFailover(); - /** - * Sets the number of allowed retransmissions for this message that can be performed - * in case of failure detection. - * - * @param arg number of allowed retransmissions - */ - void setNumberOfRetransAllowed(int arg); + /** + * Sets the number of allowed retransmissions for this message that can be performed + * in case of failure detection. + * + * @param arg number of allowed retransmissions + */ + void setNumberOfRetransAllowed(int arg); - /** - * Decrements the number of allowed retransmissions for this message. - */ - void decrementNumberOfRetransAllowed(); - } + /** + * Decrements the number of allowed retransmissions for this message. + */ + void decrementNumberOfRetransAllowed(); +} diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java index 047856abb..5f064f6c5 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java @@ -1,136 +1,136 @@ - /* - * 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 - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * JBoss, Home of Professional Open Source - * Copyright 2007-2011, Red Hat, Inc. and individual contributors - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ +/* +* 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 +* +* This file incorporates work covered by the following copyright and +* permission notice: +* +* JBoss, Home of Professional Open Source +* Copyright 2007-2011, Red Hat, Inc. and individual contributors +* by the @authors tag. See the copyright.txt in the distribution for a +* full listing of individual contributors. +* +* This is free software; you can redistribute it and/or modify it +* under the terms of the GNU Lesser General Public License as +* published by the Free Software Foundation; either version 2.1 of +* the License, or (at your option) any later version. +* +* This software 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this software; if not, write to the Free +* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA, or see the FSF site: http://www.fsf.org. +*/ package org.jdiameter.client.impl.parser; - import org.jdiameter.api.Avp; - import org.jdiameter.api.AvpDataException; - import org.jdiameter.client.api.app.cca.ICCAMessage; - import org.slf4j.Logger; - import org.slf4j.LoggerFactory; - - - /** - * Represents a Diameter message. - * - * @author erick.svenson@yahoo.com - * @author Alexandre Mendonca - * @author Bartosz Baranowski - * @author Grzegorz Figiel (ProIDS sp. z o.o.) - */ - public class CCAMessageImpl extends MessageImpl implements ICCAMessage { - - private static final Logger logger = LoggerFactory.getLogger(CCAMessageImpl.class); - - boolean isRetransSupervisionActive = false; - int numberOfRetransAllowed = Integer.MIN_VALUE; - - /** - * Create empty message - * - * @param commandCode - * @param appId - */ - CCAMessageImpl(int commandCode, long appId) { - super(commandCode, appId); - } - - /** - * Create empty message - * - * @param commandCode - * @param applicationId - * @param flags - * @param hopByHopId - * @param endToEndId - * @param avpSet - */ - CCAMessageImpl(int commandCode, long applicationId, short flags, long hopByHopId, long endToEndId, AvpSetImpl avpSet) { - super(commandCode, applicationId, flags, hopByHopId, endToEndId, avpSet); - } - - /** - * Create Answer - * - * @param request parent request - */ - private CCAMessageImpl(CCAMessageImpl request) { - super(request); - } - - @Override - public boolean isRetransmissionSupervised() { - return this.isRetransSupervisionActive; - } - - public void setRetransmissionSupervised(boolean arg) { - this.isRetransSupervisionActive = arg; - } - - public boolean isRetransmissionAllowed() { - return this.numberOfRetransAllowed > 0; - } - - public int getCcSessionFailover() { - try { - Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); - if (avpCcSessionFailover != null) { - return avpCcSessionFailover.getInteger32(); - } - } - catch (AvpDataException ade) { - logger.error("Failed to fetch CC-Session-Failover", ade); - } - return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; - } - - public void setNumberOfRetransAllowed(int arg) { - if (this.numberOfRetransAllowed < 0) { - this.numberOfRetransAllowed = arg; - } - } - - public void decrementNumberOfRetransAllowed() { - this.numberOfRetransAllowed--; - } - - } +import org.jdiameter.api.Avp; +import org.jdiameter.api.AvpDataException; +import org.jdiameter.client.api.app.cca.ICCAMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Represents a Diameter message. + * + * @author erick.svenson@yahoo.com + * @author Alexandre Mendonca + * @author Bartosz Baranowski + * @author Grzegorz Figiel (ProIDS sp. z o.o.) + */ +public class CCAMessageImpl extends MessageImpl implements ICCAMessage { + + private static final Logger logger = LoggerFactory.getLogger(CCAMessageImpl.class); + + boolean isRetransSupervisionActive = false; + int numberOfRetransAllowed = Integer.MIN_VALUE; + + /** + * Create empty message + * + * @param commandCode + * @param appId + */ + CCAMessageImpl(int commandCode, long appId) { + super(commandCode, appId); + } + + /** + * Create empty message + * + * @param commandCode + * @param applicationId + * @param flags + * @param hopByHopId + * @param endToEndId + * @param avpSet + */ + CCAMessageImpl(int commandCode, long applicationId, short flags, long hopByHopId, long endToEndId, AvpSetImpl avpSet) { + super(commandCode, applicationId, flags, hopByHopId, endToEndId, avpSet); + } + + /** + * Create Answer + * + * @param request parent request + */ + private CCAMessageImpl(MessageImpl request) { + super(request); + } + + @Override + public boolean isRetransmissionSupervised() { + return this.isRetransSupervisionActive; + } + + public void setRetransmissionSupervised(boolean arg) { + this.isRetransSupervisionActive = arg; + } + + public boolean isRetransmissionAllowed() { + return this.numberOfRetransAllowed > 0; + } + + public int getCcSessionFailover() { + try { + Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); + if (avpCcSessionFailover != null) { + return avpCcSessionFailover.getInteger32(); + } + } + catch (AvpDataException ade) { + logger.error("Failed to fetch CC-Session-Failover", ade); + } + return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + } + + public void setNumberOfRetransAllowed(int arg) { + if (this.numberOfRetransAllowed < 0) { + this.numberOfRetransAllowed = arg; + } + } + + public void decrementNumberOfRetransAllowed() { + this.numberOfRetransAllowed--; + } + +} From 0360248cf5d477cfa10579a6cc50976e8b6259a4 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 6 Jul 2017 10:24:36 +0200 Subject: [PATCH 10/26] fix --- .../jdiameter/client/impl/router/FailureAwareRouter.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java index c003c1217..16d16b04b 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java @@ -28,10 +28,13 @@ import org.jdiameter.api.RouteException; import org.jdiameter.client.api.IContainer; import org.jdiameter.client.api.IMessage; +import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.controller.IPeer; import org.jdiameter.client.api.controller.IPeerTable; import org.jdiameter.client.api.controller.IRealm; import org.jdiameter.client.api.controller.IRealmTable; +import org.jdiameter.client.impl.parser.CCAMessageImpl; +import org.jdiameter.client.impl.parser.MessageImpl; import org.jdiameter.common.api.concurrent.IConcurrentFactory; import org.jdiameter.common.api.data.IRoutingAwareSessionDatasource; import org.jdiameter.common.api.data.ISessionDatasource; @@ -79,8 +82,8 @@ public FailureAwareRouter(IContainer container, IConcurrentFactory concurrentFac * Narrows down the subset of peers selected by {@link RouterImpl} superclass to those with * the highest rating only. */ - protected List getAvailablePeers(String destRealm, String[] peers, IPeerTable manager, IMessage message) { - List selectedPeers = getAvailablePeers(destRealm, peers, manager, message); + protected List getAvailablePeers(String destRealm, String[] peers, IPeerTable manager, ICCAMessage message) { + List selectedPeers = getPeers(destRealm, peers, manager, PeerState.OKAY); if (logger.isDebugEnabled()) { logger.debug("All available peers: {}", selectedPeers); @@ -215,7 +218,7 @@ public IPeer getPeer(IMessage message, IPeerTable manager) throws RouteException throw new RouteException("Unable to find context by route information [" + destRealm + " ," + destHost + "]"); } - List availablePeers = getAvailablePeers(destRealm, peers, manager, message); + List availablePeers = getAvailablePeers(destRealm, peers, manager, (ICCAMessage) message); if (logger.isDebugEnabled()) { logger.debug("Performing Realm routing. Realm [{}] has the following peers available [{}] from list [{}]", From 7583b7a1ac11a0973847b0668686722dc3d500c4 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 6 Jul 2017 11:55:05 +0200 Subject: [PATCH 11/26] 1. revert some changes from commit f31450bd41977c9ac874501354c816c26b884f2b 2. CCAMessage handled --- .../ro/ClientRoSessionDataReplicatedImpl.java | 4 ++-- .../client/api/parser/IMessageParser.java | 20 +++++++++++++++++-- .../impl/app/ro/ClientRoSessionImpl.java | 17 ++++++++-------- .../client/impl/controller/PeerImpl.java | 3 ++- .../client/impl/parser/CCAMessageImpl.java | 10 +++------- .../client/impl/parser/MessageImpl.java | 2 +- .../client/impl/parser/MessageParser.java | 14 +++++++++++++ .../impl/router/FailureAwareRouter.java | 2 -- 8 files changed, 48 insertions(+), 24 deletions(-) diff --git a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java index 91314f0de..d47b82366 100644 --- a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java +++ b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java @@ -215,7 +215,7 @@ public Request getTxTimerRequest() { byte[] data = (byte[]) getNode().get(TXTIMER_REQUEST); if (data != null) { try { - return this.messageParser.createMessage(ByteBuffer.wrap(data)); + return this.messageParser.createCCAMessage(ByteBuffer.wrap(data)); } catch (AvpDataException e) { logger.error("Unable to recreate Tx Timer Request from buffer."); @@ -257,7 +257,7 @@ public Request getBuffer() { byte[] data = (byte[]) getNode().get(BUFFER); if (data != null) { try { - return this.messageParser.createMessage(ByteBuffer.wrap(data)); + return this.messageParser.createCCAMessage(ByteBuffer.wrap(data)); } catch (AvpDataException e) { logger.error("Unable to recreate message from buffer."); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java index a8254d19c..84138db28 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java @@ -46,8 +46,9 @@ import org.jdiameter.api.AvpDataException; import org.jdiameter.client.api.IMessage; +import org.jdiameter.client.api.app.cca.ICCAMessage; -/** + /** * Basic interface for diameter message parsers. * * @author erick.svenson@yahoo.com @@ -64,14 +65,29 @@ public interface IMessageParser { */ IMessage createMessage(ByteBuffer data) throws AvpDataException; + /** + * Create message from bytebuffer + * @param data message bytebuffer + * @return instance of message + * @throws AvpDataException + */ + ICCAMessage createCCAMessage(ByteBuffer data) throws AvpDataException; + /** * Create message from byte array - * @param data message byte array * @return instance of message * @throws AvpDataException */ IMessage createMessage(byte[] message) throws AvpDataException; + /** + * Create message from byte array + * + * @return instance of message + * @throws AvpDataException + */ + ICCAMessage createCCAMessage(byte[] message) throws AvpDataException; + /** * Created specified type of message * @param iface type of message diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index a0be3d1a5..6027fc3f5 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -408,7 +408,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx } } else if (retrRequiredErrorCodes.contains(resultCode)) { - handleRetransmissionDueToError(eventType, localEvent.getRequest().getMessage()); + handleRetransmissionDueToError(eventType, (ICCAMessage) localEvent.getRequest().getMessage()); break; } else if (isProvisional(resultCode) || isFailure(resultCode)) { @@ -551,7 +551,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { setState(ClientRoSessionState.OPEN); } else if (retrRequiredErrorCodes.contains(resultCode)) { - handleRetransmissionDueToError(eventType, localEvent.getRequest().getMessage()); + handleRetransmissionDueToError(eventType, (ICCAMessage) localEvent.getRequest().getMessage()); break; } else if (isProvisional(resultCode) || isFailure(resultCode)) { @@ -636,7 +636,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { sessionData.setGatheredCCSF(((ICCAMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = ((AppAnswerEvent) localEvent.getAnswer()).getResultCodeAvp().getUnsigned32(); if (retrRequiredErrorCodes.contains(resultCode)) { - handleRetransmissionDueToError(eventType, localEvent.getRequest().getMessage()); + handleRetransmissionDueToError(eventType, (ICCAMessage) localEvent.getRequest().getMessage()); break; } @@ -1352,15 +1352,14 @@ protected void handleRetransmission(Type eventType, ICCAMessage msg, boolean tFl } } - protected void handleRetransmissionDueToError(Type eventType, Message msg) { - ICCAMessage imsg = (ICCAMessage) msg; + protected void handleRetransmissionDueToError(Type eventType, ICCAMessage msg) { logger.warn("Message will be retransmitted due to error response [{}] ", msg); try { - if (imsg.isRetransmissionAllowed()) { + if (msg.isRetransmissionAllowed()) { if (isSessionFailoverSupported()) { - handleRetransmission(eventType, imsg, false); - imsg.decrementNumberOfRetransAllowed(); + handleRetransmission(eventType, msg, false); + msg.decrementNumberOfRetransAllowed(); } else { handleSendFailure(new Exception("Failover unsupported for session ID: " + sessionData.getSessionId()), eventType, msg); @@ -1637,7 +1636,7 @@ private Message messageFromBuffer(ByteBuffer request) throws InternalException { if (request != null) { Message m; try { - m = parser.createMessage(request); + m = parser.createCCAMessage(request); return m; } catch (AvpDataException e) { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java index 083f92727..6aeb352b1 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java @@ -110,6 +110,7 @@ import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.IMetaData; import org.jdiameter.client.api.IRequest; +import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.controller.IPeer; import org.jdiameter.client.api.fsm.EventTypes; import org.jdiameter.client.api.fsm.FsmEvent; @@ -192,7 +193,7 @@ public void connectionOpened(String connKey) { public void connectionClosed(String connKey, List notSent) { logger.debug("Connection from {} is closed", uri); for (IMessage request : peerRequests.values()) { - if (request.getState() == IMessage.STATE_SENT && !request.isRetransmissionSupervised()) { + if (request.getState() == IMessage.STATE_SENT && !((ICCAMessage) request).isRetransmissionSupervised()) { request.setReTransmitted(true); request.setState(IMessage.STATE_NOT_SENT); try { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java index 5f064f6c5..ac775c44c 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java @@ -88,13 +88,9 @@ public class CCAMessageImpl extends MessageImpl implements ICCAMessage { super(commandCode, applicationId, flags, hopByHopId, endToEndId, avpSet); } - /** - * Create Answer - * - * @param request parent request - */ - private CCAMessageImpl(MessageImpl request) { - super(request); + public CCAMessageImpl(MessageImpl message) { + super(message.getCommandCode(), message.getApplicationId(), (short) message.getFlags(), message.getHopByHopIdentifier(), message.getEndToEndIdentifier(), + (AvpSetImpl) message.getAvps()); } @Override diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java index 4f233d536..a743bc299 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java @@ -155,7 +155,7 @@ public class MessageImpl implements IMessage { * * @param request parent request */ - MessageImpl(MessageImpl request) { + private MessageImpl(MessageImpl request) { this(request.getCommandCode(), request.getHeaderApplicationId()); copyHeader(request); setRequest(false); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java index b46f59041..c1a51c390 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java @@ -60,6 +60,7 @@ import org.jdiameter.api.Request; import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.IRequest; +import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.client.api.parser.ParseException; import org.jdiameter.client.impl.helpers.UIDGenerator; @@ -128,10 +129,23 @@ public IMessage createMessage(ByteBuffer data) throws AvpDataException { return createMessage(message); } + @Override + public ICCAMessage createCCAMessage(byte[] message) throws AvpDataException { + return new CCAMessageImpl((CCAMessageImpl)createMessage(message)); + } + + @Override + public ICCAMessage createCCAMessage(ByteBuffer data) throws AvpDataException { + byte[] message = data.array(); + return createCCAMessage(message); + } + @Override public T createMessage(Class iface, ByteBuffer data) throws AvpDataException { if (iface == IMessage.class) { return (T) createMessage(data); + } else if (iface == ICCAMessage.class) { + return (T) createCCAMessage(data); } return null; } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java index 16d16b04b..17530c023 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java @@ -33,8 +33,6 @@ import org.jdiameter.client.api.controller.IPeerTable; import org.jdiameter.client.api.controller.IRealm; import org.jdiameter.client.api.controller.IRealmTable; -import org.jdiameter.client.impl.parser.CCAMessageImpl; -import org.jdiameter.client.impl.parser.MessageImpl; import org.jdiameter.common.api.concurrent.IConcurrentFactory; import org.jdiameter.common.api.data.IRoutingAwareSessionDatasource; import org.jdiameter.common.api.data.ISessionDatasource; From 5c2e50ff80c9170a2e019270c8fe7b61bcb4c33b Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 6 Jul 2017 16:45:19 +0200 Subject: [PATCH 12/26] parameters order kept --- .../main/java/org/jdiameter/api/ro/ClientRoSessionListener.java | 2 +- .../org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java | 2 +- .../org/jdiameter/common/impl/app/ro/RoSessionFactoryImpl.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java index 839ff5d95..f4277bbe2 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/ro/ClientRoSessionListener.java @@ -145,7 +145,7 @@ void doRequestTimeout(ClientRoSession session, Message msg, Peer peer) * @throws RouteException The NoRouteException signals that no route exist for a given realm. * @throws OverloadException The OverloadException signals that destination host is overloaded. */ - void doPeerUnavailability(RouteException cause, ClientRoSession session, Message msg, Peer peer) + void doPeerUnavailability(ClientRoSession session, Message msg, Peer peer, RouteException cause) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException; /** diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 6027fc3f5..603fac907 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -1480,7 +1480,7 @@ protected void deliverPeerUnavailabilityError(Message msg, NoMorePeersAvailableE logger.debug("Propagating peer unavailability error event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { - listener.doPeerUnavailability(cause, this, msg, ((ICCAMessage) msg).getPeer()); + listener.doPeerUnavailability(this, msg, ((ICCAMessage) msg).getPeer(), cause); } } catch (Exception e) { 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 580dc4978..825f5eeef 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 @@ -388,7 +388,7 @@ public void doRequestTimeout(ClientRoSession session, Message msg, Peer peer) th } @Override - public void doPeerUnavailability(RouteException cause, ClientRoSession session, Message msg, Peer peer) throws InternalException { + public void doPeerUnavailability(ClientRoSession session, Message msg, Peer peer, RouteException cause) throws InternalException { } From 7e099ffc31d650af092792cdc1582bfa8055b48a Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Tue, 11 Jul 2017 15:15:18 +0200 Subject: [PATCH 13/26] 1. testsuite ClassCastException fixed 2. possbile ClassCastException in PeerImpl fixed --- .../java/org/jdiameter/client/impl/controller/PeerImpl.java | 2 +- .../jdiameter/common/impl/app/cca/CCASessionFactoryImpl.java | 2 +- .../mobicents/diameter/stack/functional/ro/base/Client.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java index 6aeb352b1..4fa71c911 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java @@ -193,7 +193,7 @@ public void connectionOpened(String connKey) { public void connectionClosed(String connKey, List notSent) { logger.debug("Connection from {} is closed", uri); for (IMessage request : peerRequests.values()) { - if (request.getState() == IMessage.STATE_SENT && !((ICCAMessage) request).isRetransmissionSupervised()) { + if (request.getState() == IMessage.STATE_SENT && !(request instanceof ICCAMessage && ((ICCAMessage) request).isRetransmissionSupervised())) {​ request.setReTransmitted(true); request.setState(IMessage.STATE_NOT_SENT); try { 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 16d575126..87696a0ac 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; diff --git a/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java b/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java index e9e114aa5..cdc7d9059 100644 --- a/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java +++ b/testsuite/tests/src/test/java/org/mobicents/diameter/stack/functional/ro/base/Client.java @@ -182,7 +182,8 @@ public void doRequestTimeout(ClientRoSession clientRoSession, Message message, P } @Override - public void doPeerUnavailability(RouteException e, ClientRoSession clientRoSession, Message message, Peer peer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + public void doPeerUnavailability(ClientRoSession clientRoSession, Message message, Peer peer, RouteException e) throws InternalException, IllegalDiameterStateException, + RouteException, OverloadException { } From e8bca24f46585dd54b48e8065abccc8579965367 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 26 Jul 2017 14:53:12 +0200 Subject: [PATCH 14/26] deleted CCAMessage --- .../ro/ClientRoSessionDataReplicatedImpl.java | 4 +- .../org/jdiameter/client/api/IMessage.java | 50 +++++++ .../client/api/app/cca/ICCAMessage.java | 78 ----------- .../client/api/parser/IMessageParser.java | 17 --- .../impl/app/ro/ClientRoSessionImpl.java | 40 +++--- .../client/impl/controller/PeerImpl.java | 3 +- .../client/impl/parser/CCAMessageImpl.java | 132 ------------------ .../client/impl/parser/MessageImpl.java | 39 ++++++ .../client/impl/parser/MessageParser.java | 14 -- .../impl/router/FailureAwareRouter.java | 5 +- .../impl/app/ro/RoSessionFactoryImpl.java | 4 +- 11 files changed, 116 insertions(+), 270 deletions(-) delete mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java delete mode 100644 core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java diff --git a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java index d47b82366..91314f0de 100644 --- a/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java +++ b/core/jdiameter-ha/impl/src/main/java/org/mobicents/diameter/impl/ha/client/ro/ClientRoSessionDataReplicatedImpl.java @@ -215,7 +215,7 @@ public Request getTxTimerRequest() { byte[] data = (byte[]) getNode().get(TXTIMER_REQUEST); if (data != null) { try { - return this.messageParser.createCCAMessage(ByteBuffer.wrap(data)); + return this.messageParser.createMessage(ByteBuffer.wrap(data)); } catch (AvpDataException e) { logger.error("Unable to recreate Tx Timer Request from buffer."); @@ -257,7 +257,7 @@ public Request getBuffer() { byte[] data = (byte[]) getNode().get(BUFFER); if (data != null) { try { - return this.messageParser.createCCAMessage(ByteBuffer.wrap(data)); + return this.messageParser.createMessage(ByteBuffer.wrap(data)); } catch (AvpDataException e) { logger.error("Unable to recreate message from buffer."); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java index bae98da48..259a70970 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java @@ -62,6 +62,16 @@ */ public interface IMessage extends IRequest, IAnswer { + /** + * 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; + /** * The message is not sent to the network */ @@ -218,4 +228,44 @@ public interface IMessage extends IRequest, IAnswer { * @return clone */ Object clone(); + + /** + * Tells if there are any timers set to monitor potential retransmissions + * + * @return true if potential retransmissions will be handled + */ + boolean isRetransmissionSupervised(); + + /** + * Marks that message to be under supervision timers guarding retransmissions + * + * @param arg true if supervision is active + */ + void setRetransmissionSupervised(boolean arg); + + /** + * Tells if the number of allowed retransmissions for this message is + * already exceeded or not. + * + * @return false if no more retransmissions are allowed + */ + boolean isRetransmissionAllowed(); + + /** + * @return value of CC-Session-Failover AVP. + */ + int getCcSessionFailover(); + + /** + * Sets the number of allowed retransmissions for this message that can be performed + * in case of failure detection. + * + * @param arg number of allowed retransmissions + */ + void setNumberOfRetransAllowed(int arg); + + /** + * Decrements the number of allowed retransmissions for this message. + */ + void decrementNumberOfRetransAllowed(); } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java deleted file mode 100644 index 12ee3bbcb..000000000 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/app/cca/ICCAMessage.java +++ /dev/null @@ -1,78 +0,0 @@ -/* -* 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.client.api.app.cca; - -import org.jdiameter.client.api.IMessage; - -/** - * @author Grzegorz Figiel (ProIDS sp. z o.o.) - */ -public interface ICCAMessage extends IMessage { - - /** - * 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; - - /** - * Tells if there are any timers set to monitor potential retransmissions - * - * @return true if potential retransmissions will be handled - */ - boolean isRetransmissionSupervised(); - - /** - * Marks that message to be under supervision timers guarding retransmissions - * - * @param arg true if supervision is active - */ - void setRetransmissionSupervised(boolean arg); - - /** - * Tells if the number of allowed retransmissions for this message is - * already exceeded or not. - * - * @return false if no more retransmissions are allowed - */ - boolean isRetransmissionAllowed(); - - /** - * @return value of CC-Session-Failover AVP. - */ - int getCcSessionFailover(); - - /** - * Sets the number of allowed retransmissions for this message that can be performed - * in case of failure detection. - * - * @param arg number of allowed retransmissions - */ - void setNumberOfRetransAllowed(int arg); - - /** - * Decrements the number of allowed retransmissions for this message. - */ - void decrementNumberOfRetransAllowed(); -} diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java index 84138db28..c319789cb 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/parser/IMessageParser.java @@ -46,7 +46,6 @@ import org.jdiameter.api.AvpDataException; import org.jdiameter.client.api.IMessage; -import org.jdiameter.client.api.app.cca.ICCAMessage; /** * Basic interface for diameter message parsers. @@ -65,14 +64,6 @@ public interface IMessageParser { */ IMessage createMessage(ByteBuffer data) throws AvpDataException; - /** - * Create message from bytebuffer - * @param data message bytebuffer - * @return instance of message - * @throws AvpDataException - */ - ICCAMessage createCCAMessage(ByteBuffer data) throws AvpDataException; - /** * Create message from byte array * @return instance of message @@ -80,14 +71,6 @@ public interface IMessageParser { */ IMessage createMessage(byte[] message) throws AvpDataException; - /** - * Create message from byte array - * - * @return instance of message - * @throws AvpDataException - */ - ICCAMessage createCCAMessage(byte[] message) throws AvpDataException; - /** * Created specified type of message * @param iface type of message diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 603fac907..5e0177a9c 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -74,8 +74,8 @@ import org.jdiameter.api.ro.events.RoCreditControlAnswer; import org.jdiameter.api.ro.events.RoCreditControlRequest; import org.jdiameter.client.api.IContainer; +import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.ISessionFactory; -import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.client.api.parser.ParseException; import org.jdiameter.client.api.router.IRouter; @@ -369,7 +369,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx setState(ClientRoSessionState.PENDING_INITIAL); // RFC 4006: For new credit-control sessions, failover to an alternative // credit-control server SHOULD be performed if possible. - sessionData.setGatheredCCSF(ICCAMessage.SESSION_FAILOVER_SUPPORTED_VALUE); + sessionData.setGatheredCCSF(IMessage.SESSION_FAILOVER_SUPPORTED_VALUE); try { dispatchEvent(localEvent.getRequest()); } @@ -391,7 +391,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx AppAnswerEvent answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_INITIAL_ANSWER: - sessionData.setGatheredCCSF(((ICCAMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_I @@ -408,7 +408,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx } } else if (retrRequiredErrorCodes.contains(resultCode)) { - handleRetransmissionDueToError(eventType, (ICCAMessage) localEvent.getRequest().getMessage()); + handleRetransmissionDueToError(eventType, (IMessage) localEvent.getRequest().getMessage()); break; } else if (isProvisional(resultCode) || isFailure(resultCode)) { @@ -540,7 +540,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_UPDATE_ANSWER: - sessionData.setGatheredCCSF(((ICCAMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_U @@ -551,7 +551,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { setState(ClientRoSessionState.OPEN); } else if (retrRequiredErrorCodes.contains(resultCode)) { - handleRetransmissionDueToError(eventType, (ICCAMessage) localEvent.getRequest().getMessage()); + handleRetransmissionDueToError(eventType, (IMessage) localEvent.getRequest().getMessage()); break; } else if (isProvisional(resultCode) || isFailure(resultCode)) { @@ -633,10 +633,10 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { //FIXME: Alex broke this, setting back "true" ? //setState(ClientRoSessionState.IDLE, false); - sessionData.setGatheredCCSF(((ICCAMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); long resultCode = ((AppAnswerEvent) localEvent.getAnswer()).getResultCodeAvp().getUnsigned32(); if (retrRequiredErrorCodes.contains(resultCode)) { - handleRetransmissionDueToError(eventType, (ICCAMessage) localEvent.getRequest().getMessage()); + handleRetransmissionDueToError(eventType, (IMessage) localEvent.getRequest().getMessage()); break; } @@ -1321,7 +1321,7 @@ protected void handlePeerUnavailability(Message msg, NoMorePeersAvailableExcepti setState(ClientRoSessionState.IDLE, true); } - protected void handleRetransmission(Type eventType, ICCAMessage msg, boolean tFlagSetting) { + protected void handleRetransmission(Type eventType, IMessage msg, boolean tFlagSetting) { msg.setReTransmitted(tFlagSetting); if (this.sessionData.getRetransmissionTimerId() == null) { startFailoverStopTimer(); @@ -1352,7 +1352,7 @@ protected void handleRetransmission(Type eventType, ICCAMessage msg, boolean tFl } } - protected void handleRetransmissionDueToError(Type eventType, ICCAMessage msg) { + protected void handleRetransmissionDueToError(Type eventType, IMessage msg) { logger.warn("Message will be retransmitted due to error response [{}] ", msg); try { @@ -1378,7 +1378,7 @@ protected void handleRetransmissionDueToError(Type eventType, ICCAMessage msg) { protected void handleRetransmissionDueToTimeout(Type eventType, AppEvent event) throws InternalException { if (isSessionFailoverSupported()) { - handleRetransmission(eventType, (ICCAMessage) event.getMessage(), true); + handleRetransmission(eventType, (IMessage) event.getMessage(), true); } else { logger.warn("Failed to send message. Failover unsupported for session ID: {}", sessionData.getSessionId()); @@ -1456,7 +1456,7 @@ protected void deliverRequestTxTimeout(Message msg) { logger.debug("Propagating Tx timeout event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { - listener.doRequestTxTimeout(this, msg, ((ICCAMessage) msg).getPeer()); + listener.doRequestTxTimeout(this, msg, ((IMessage) msg).getPeer()); } } catch (Exception e) { @@ -1468,7 +1468,7 @@ protected void deliverRequestTimeout(Message msg) { logger.debug("Propagating timeout event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { - listener.doRequestTimeout(this, msg, ((ICCAMessage) msg).getPeer()); + listener.doRequestTimeout(this, msg, ((IMessage) msg).getPeer()); } } catch (Exception e) { @@ -1480,7 +1480,7 @@ protected void deliverPeerUnavailabilityError(Message msg, NoMorePeersAvailableE logger.debug("Propagating peer unavailability error event to listener [{}] on {} session", listener, isValid() ? "valid" : "invalid"); try { if (isValid()) { - listener.doPeerUnavailability(this, msg, ((ICCAMessage) msg).getPeer(), cause); + listener.doPeerUnavailability(this, msg, ((IMessage) msg).getPeer(), cause); } } catch (Exception e) { @@ -1530,7 +1530,7 @@ else if (request != null) { } } - protected void dispatchEvent(ICCAMessage message) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { + protected void dispatchEvent(IMessage message) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { if (message.isRequest()) { message.setRetransmissionSupervised(true); } @@ -1538,7 +1538,7 @@ protected void dispatchEvent(ICCAMessage message) throws InternalException, Ille } protected void dispatchEvent(AppEvent event) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { - dispatchEvent((ICCAMessage) event.getMessage()); + dispatchEvent((IMessage) event.getMessage()); } protected boolean isProvisional(long resultCode) { @@ -1636,7 +1636,7 @@ private Message messageFromBuffer(ByteBuffer request) throws InternalException { if (request != null) { Message m; try { - m = parser.createCCAMessage(request); + m = parser.createMessage(request); return m; } catch (AvpDataException e) { @@ -1646,7 +1646,7 @@ private Message messageFromBuffer(ByteBuffer request) throws InternalException { return null; } - private ByteBuffer messageToBuffer(ICCAMessage msg) throws InternalException { + private ByteBuffer messageToBuffer(IMessage msg) throws InternalException { try { return parser.encodeMessage(msg); } @@ -1656,9 +1656,9 @@ private ByteBuffer messageToBuffer(ICCAMessage msg) throws InternalException { } private void resetMessageStatus(Message message) { - ICCAMessage msg = (ICCAMessage) message; + IMessage msg = (IMessage) message; msg.clearTimer(); - msg.setState(ICCAMessage.STATE_NOT_SENT); + msg.setState(IMessage.STATE_NOT_SENT); if (msg.getPeer() != null) { msg.getPeer().remMessage(msg); } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java index 4fa71c911..083f92727 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/controller/PeerImpl.java @@ -110,7 +110,6 @@ import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.IMetaData; import org.jdiameter.client.api.IRequest; -import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.controller.IPeer; import org.jdiameter.client.api.fsm.EventTypes; import org.jdiameter.client.api.fsm.FsmEvent; @@ -193,7 +192,7 @@ public void connectionOpened(String connKey) { public void connectionClosed(String connKey, List notSent) { logger.debug("Connection from {} is closed", uri); for (IMessage request : peerRequests.values()) { - if (request.getState() == IMessage.STATE_SENT && !(request instanceof ICCAMessage && ((ICCAMessage) request).isRetransmissionSupervised())) {​ + if (request.getState() == IMessage.STATE_SENT && !request.isRetransmissionSupervised()) { request.setReTransmitted(true); request.setState(IMessage.STATE_NOT_SENT); try { diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java deleted file mode 100644 index ac775c44c..000000000 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/CCAMessageImpl.java +++ /dev/null @@ -1,132 +0,0 @@ -/* -* 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 -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* JBoss, Home of Professional Open Source -* Copyright 2007-2011, Red Hat, Inc. and individual contributors -* by the @authors tag. See the copyright.txt in the distribution for a -* full listing of individual contributors. -* -* This is free software; you can redistribute it and/or modify it -* under the terms of the GNU Lesser General Public License as -* published by the Free Software Foundation; either version 2.1 of -* the License, or (at your option) any later version. -* -* This software 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this software; if not, write to the Free -* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -* 02110-1301 USA, or see the FSF site: http://www.fsf.org. -*/ - -package org.jdiameter.client.impl.parser; - -import org.jdiameter.api.Avp; -import org.jdiameter.api.AvpDataException; -import org.jdiameter.client.api.app.cca.ICCAMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Represents a Diameter message. - * - * @author erick.svenson@yahoo.com - * @author Alexandre Mendonca - * @author Bartosz Baranowski - * @author Grzegorz Figiel (ProIDS sp. z o.o.) - */ -public class CCAMessageImpl extends MessageImpl implements ICCAMessage { - - private static final Logger logger = LoggerFactory.getLogger(CCAMessageImpl.class); - - boolean isRetransSupervisionActive = false; - int numberOfRetransAllowed = Integer.MIN_VALUE; - - /** - * Create empty message - * - * @param commandCode - * @param appId - */ - CCAMessageImpl(int commandCode, long appId) { - super(commandCode, appId); - } - - /** - * Create empty message - * - * @param commandCode - * @param applicationId - * @param flags - * @param hopByHopId - * @param endToEndId - * @param avpSet - */ - CCAMessageImpl(int commandCode, long applicationId, short flags, long hopByHopId, long endToEndId, AvpSetImpl avpSet) { - super(commandCode, applicationId, flags, hopByHopId, endToEndId, avpSet); - } - - public CCAMessageImpl(MessageImpl message) { - super(message.getCommandCode(), message.getApplicationId(), (short) message.getFlags(), message.getHopByHopIdentifier(), message.getEndToEndIdentifier(), - (AvpSetImpl) message.getAvps()); - } - - @Override - public boolean isRetransmissionSupervised() { - return this.isRetransSupervisionActive; - } - - public void setRetransmissionSupervised(boolean arg) { - this.isRetransSupervisionActive = arg; - } - - public boolean isRetransmissionAllowed() { - return this.numberOfRetransAllowed > 0; - } - - public int getCcSessionFailover() { - try { - Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); - if (avpCcSessionFailover != null) { - return avpCcSessionFailover.getInteger32(); - } - } - catch (AvpDataException ade) { - logger.error("Failed to fetch CC-Session-Failover", ade); - } - return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; - } - - public void setNumberOfRetransAllowed(int arg) { - if (this.numberOfRetransAllowed < 0) { - this.numberOfRetransAllowed = arg; - } - } - - public void decrementNumberOfRetransAllowed() { - this.numberOfRetransAllowed--; - } - -} diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java index a743bc299..74ca170e7 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java @@ -97,6 +97,9 @@ public class MessageImpl implements IMessage { // Potential place for dirt, but Application IDs don't change during message life time. transient List applicationIds; + boolean isRetransSupervisionActive = false; + int numberOfRetransAllowed = Integer.MIN_VALUE; + /** * Create empty message * @@ -611,6 +614,42 @@ public Object clone() { } } + @Override + public boolean isRetransmissionSupervised() { + return this.isRetransSupervisionActive; + } + + public void setRetransmissionSupervised(boolean arg) { + this.isRetransSupervisionActive = arg; + } + + public boolean isRetransmissionAllowed() { + return this.numberOfRetransAllowed > 0; + } + + public int getCcSessionFailover() { + try { + Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); + if (avpCcSessionFailover != null) { + return avpCcSessionFailover.getInteger32(); + } + } + catch (AvpDataException ade) { + logger.error("Failed to fetch CC-Session-Failover", ade); + } + return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + } + + public void setNumberOfRetransAllowed(int arg) { + if (this.numberOfRetransAllowed < 0) { + this.numberOfRetransAllowed = arg; + } + } + + public void decrementNumberOfRetransAllowed() { + this.numberOfRetransAllowed--; + } + protected static class TimerTask implements Runnable { ScheduledFuture timerHandler; diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java index c1a51c390..b46f59041 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageParser.java @@ -60,7 +60,6 @@ import org.jdiameter.api.Request; import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.IRequest; -import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.client.api.parser.ParseException; import org.jdiameter.client.impl.helpers.UIDGenerator; @@ -129,23 +128,10 @@ public IMessage createMessage(ByteBuffer data) throws AvpDataException { return createMessage(message); } - @Override - public ICCAMessage createCCAMessage(byte[] message) throws AvpDataException { - return new CCAMessageImpl((CCAMessageImpl)createMessage(message)); - } - - @Override - public ICCAMessage createCCAMessage(ByteBuffer data) throws AvpDataException { - byte[] message = data.array(); - return createCCAMessage(message); - } - @Override public T createMessage(Class iface, ByteBuffer data) throws AvpDataException { if (iface == IMessage.class) { return (T) createMessage(data); - } else if (iface == ICCAMessage.class) { - return (T) createCCAMessage(data); } return null; } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java index 17530c023..2594a3dca 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/router/FailureAwareRouter.java @@ -28,7 +28,6 @@ import org.jdiameter.api.RouteException; import org.jdiameter.client.api.IContainer; import org.jdiameter.client.api.IMessage; -import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.api.controller.IPeer; import org.jdiameter.client.api.controller.IPeerTable; import org.jdiameter.client.api.controller.IRealm; @@ -80,7 +79,7 @@ public FailureAwareRouter(IContainer container, IConcurrentFactory concurrentFac * Narrows down the subset of peers selected by {@link RouterImpl} superclass to those with * the highest rating only. */ - protected List getAvailablePeers(String destRealm, String[] peers, IPeerTable manager, ICCAMessage message) { + protected List getAvailablePeers(String destRealm, String[] peers, IPeerTable manager, IMessage message) { List selectedPeers = getPeers(destRealm, peers, manager, PeerState.OKAY); if (logger.isDebugEnabled()) { @@ -216,7 +215,7 @@ public IPeer getPeer(IMessage message, IPeerTable manager) throws RouteException throw new RouteException("Unable to find context by route information [" + destRealm + " ," + destHost + "]"); } - List availablePeers = getAvailablePeers(destRealm, peers, manager, (ICCAMessage) message); + List availablePeers = getAvailablePeers(destRealm, peers, manager, message); if (logger.isDebugEnabled()) { logger.debug("Performing Realm routing. Realm [{}] has the following peers available [{}] from list [{}]", 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 825f5eeef..a2e1888cc 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 @@ -41,8 +41,8 @@ import org.jdiameter.api.ro.ServerRoSessionListener; import org.jdiameter.api.ro.events.RoCreditControlAnswer; import org.jdiameter.api.ro.events.RoCreditControlRequest; +import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.ISessionFactory; -import org.jdiameter.client.api.app.cca.ICCAMessage; import org.jdiameter.client.impl.app.ro.ClientRoSessionImpl; import org.jdiameter.client.impl.app.ro.IClientRoSessionData; import org.jdiameter.common.api.app.IAppSessionDataFactory; @@ -72,7 +72,7 @@ public class RoSessionFactoryImpl implements IRoSessionFactory, ClientRoSessionL // Message timeout value (in milliseconds) protected int defaultDirectDebitingFailureHandling = 0; protected int defaultCreditControlFailureHandling = 0; - protected int defaultCreditControlSessionFailover = ICCAMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + protected int defaultCreditControlSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; // its seconds protected long defaultValidityTime = 60; From 4fd806e25e54125a3fa739d83b93d28a20ea2985 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Wed, 26 Jul 2017 15:39:45 +0200 Subject: [PATCH 15/26] removed getCcSessionFailover method --- .../org/jdiameter/client/api/IMessage.java | 5 --- .../impl/app/ro/ClientRoSessionImpl.java | 42 +++++++++++++++++-- .../client/impl/parser/MessageImpl.java | 13 ------ 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java index 259a70970..4800749ef 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java @@ -251,11 +251,6 @@ public interface IMessage extends IRequest, IAnswer { */ boolean isRetransmissionAllowed(); - /** - * @return value of CC-Session-Failover AVP. - */ - int getCcSessionFailover(); - /** * Sets the number of allowed retransmissions for this message that can be performed * in case of failure detection. diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 5e0177a9c..31f27a6d2 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -52,6 +52,7 @@ import java.util.concurrent.locks.ReentrantLock; import org.jdiameter.api.Answer; +import org.jdiameter.api.Avp; import org.jdiameter.api.AvpDataException; import org.jdiameter.api.EventListener; import org.jdiameter.api.IllegalDiameterStateException; @@ -391,7 +392,19 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx AppAnswerEvent answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_INITIAL_ANSWER: - sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + + Message message = localEvent.getAnswer().getMessage(); + int ccSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + + Avp avpCcSessionFailover = message.getAvps().getAvp(Avp.CC_SESSION_FAILOVER); + if (avpCcSessionFailover != null) { + ccSessionFailover = avpCcSessionFailover.getInteger32(); + } + else { + logger.warn("Failed to fetch CC-Session-Failover"); + } + + sessionData.setGatheredCCSF(ccSessionFailover); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_I @@ -540,7 +553,19 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { answer = (AppAnswerEvent) localEvent.getAnswer(); switch (eventType) { case RECEIVED_UPDATE_ANSWER: - sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + + Message message = localEvent.getAnswer().getMessage(); + int ccSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + + Avp avpCcSessionFailover = message.getAvps().getAvp(Avp.CC_SESSION_FAILOVER); + if (avpCcSessionFailover != null) { + ccSessionFailover = avpCcSessionFailover.getInteger32(); + } + else { + logger.warn("Failed to fetch CC-Session-Failover"); + } + + sessionData.setGatheredCCSF(ccSessionFailover); long resultCode = answer.getResultCodeAvp().getUnsigned32(); if (isSuccess(resultCode)) { // Current State: PENDING_U @@ -633,7 +658,18 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { //FIXME: Alex broke this, setting back "true" ? //setState(ClientRoSessionState.IDLE, false); - sessionData.setGatheredCCSF(((IMessage) localEvent.getAnswer().getMessage()).getCcSessionFailover()); + Message message = localEvent.getAnswer().getMessage(); + int ccSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + + Avp avpCcSessionFailover = message.getAvps().getAvp(Avp.CC_SESSION_FAILOVER); + if (avpCcSessionFailover != null) { + ccSessionFailover = avpCcSessionFailover.getInteger32(); + } + else { + logger.warn("Failed to fetch CC-Session-Failover"); + } + + sessionData.setGatheredCCSF(ccSessionFailover); long resultCode = ((AppAnswerEvent) localEvent.getAnswer()).getResultCodeAvp().getUnsigned32(); if (retrRequiredErrorCodes.contains(resultCode)) { handleRetransmissionDueToError(eventType, (IMessage) localEvent.getRequest().getMessage()); diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java index 74ca170e7..90f9f12fc 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/MessageImpl.java @@ -627,19 +627,6 @@ public boolean isRetransmissionAllowed() { return this.numberOfRetransAllowed > 0; } - public int getCcSessionFailover() { - try { - Avp avpCcSessionFailover = avpSet.getAvp(Avp.CC_SESSION_FAILOVER); - if (avpCcSessionFailover != null) { - return avpCcSessionFailover.getInteger32(); - } - } - catch (AvpDataException ade) { - logger.error("Failed to fetch CC-Session-Failover", ade); - } - return SESSION_FAILOVER_NOT_SUPPORTED_VALUE; - } - public void setNumberOfRetransAllowed(int arg) { if (this.numberOfRetransAllowed < 0) { this.numberOfRetransAllowed = arg; From f96d30fdc1350bd992fcba5c70d22cdad5c9a04a Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 27 Jul 2017 14:36:08 +0200 Subject: [PATCH 16/26] fix backward compability issue with ClientCCASessionImpl contructor --- .../jdiameter/client/api/ISessionFactory.java | 7 ++++ .../client/impl/SessionFactoryImpl.java | 12 +++++++ .../impl/app/cca/ClientCCASessionImpl.java | 34 ++++++++++++++++--- .../impl/app/ro/ClientRoSessionImpl.java | 10 +++--- .../impl/app/AppRoutingAwareSessionImpl.java | 11 ++---- .../impl/app/cca/CCASessionFactoryImpl.java | 20 ++++++++--- 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/ISessionFactory.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/ISessionFactory.java index 5be96d93d..a559771da 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/ISessionFactory.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/ISessionFactory.java @@ -103,4 +103,11 @@ T getNewAppSession(String sessionId, ApplicationId applic */ IContainer getContainer(); + /** + * Tells whether session persistent routing is enabled for session created by this factory. + * + * @return true if enabled + */ + boolean isSessionPersistenceEnabled(); + } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionFactoryImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionFactoryImpl.java index 12b4e4c1a..6492f9d19 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionFactoryImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/SessionFactoryImpl.java @@ -55,6 +55,7 @@ import org.jdiameter.client.api.StackState; import org.jdiameter.client.impl.helpers.UIDGenerator; import org.jdiameter.common.api.app.IAppSessionFactory; +import org.jdiameter.common.api.data.IRoutingAwareSessionDatasource; import org.jdiameter.common.api.data.ISessionDatasource; /** @@ -68,6 +69,8 @@ public class SessionFactoryImpl implements ISessionFactory { private IContainer stack; + private boolean isSessionPersistenceEnabled = false; + @SuppressWarnings("rawtypes") private Map appFactories = new ConcurrentHashMap(); private ISessionDatasource dataSource; @@ -77,6 +80,10 @@ public class SessionFactoryImpl implements ISessionFactory { public SessionFactoryImpl(IContainer stack) { this.stack = stack; this.dataSource = this.stack.getAssemblerFacility().getComponentInstance(ISessionDatasource.class); + + if(dataSource instanceof IRoutingAwareSessionDatasource) { + isSessionPersistenceEnabled = true; + } } @Override @@ -184,4 +191,9 @@ public IContainer getContainer() { return stack; } + @Override + public boolean isSessionPersistenceEnabled() { + return isSessionPersistenceEnabled; + } + } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java index 888135961..4a7db3a58 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java @@ -150,6 +150,29 @@ public class ClientCCASessionImpl extends AppCCASessionImpl implements ClientCCA temporaryErrorCodes = Collections.unmodifiableSet(tmp); } + public ClientCCASessionImpl(IClientCCASessionData data, ICCAMessageFactory fct, ISessionFactory sf, ClientCCASessionListener lst, + IClientCCASessionContext ctx, StateChangeListener stLst) { + super(null, sf, data); + if (lst == null) { + throw new IllegalArgumentException("Listener can not be null"); + } + if (data == null) { + throw new IllegalArgumentException("SessionData can not be null"); + } + if (fct.getApplicationIds() == null) { + throw new IllegalArgumentException("ApplicationId can not be less than zero"); + } + + this.sessionData = data; + this.context = ctx; + + this.authAppIds = fct.getApplicationIds(); + this.listener = lst; + this.factory = fct; + super.addStateChangeNotification(stLst); + + } + public ClientCCASessionImpl(IClientCCASessionData data, ICCAMessageFactory fct, ISessionDatasource sds, ISessionFactory sf, ClientCCASessionListener lst, IClientCCASessionContext ctx, StateChangeListener stLst) { super(sds, sf, data); @@ -356,7 +379,8 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx setState(ClientCCASessionState.OPEN); //Session persistence record shall be created after a peer had answered the //first (initial) request for that session - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { + initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); startSessionInactivityTimer(); } @@ -411,7 +435,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Action: Send RAA followed by CC update request, start Tx // New State: PENDING_U startTx((JCreditControlRequest) localEvent.getRequest()); - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { startSessionInactivityTimer(); } setState(ClientCCASessionState.PENDING_UPDATE); @@ -438,7 +462,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Event: User service terminated // Action: Send CC termination request // New State: PENDING_T - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { stopSessionInactivityTimer(); } setState(ClientCCASessionState.PENDING_TERMINATION); @@ -675,7 +699,7 @@ protected void setState(ClientCCASessionState newState, boolean release) { } stopTx(); - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { stopSessionInactivityTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); @@ -1140,7 +1164,7 @@ else if (gatheredRequestedAction == REFUND_ACCOUNT) { // Action: Grant service to end user // New State: PENDING_U context.grantAccessOnTxExpire(this); - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { stopSessionInactivityTimer(); } break; diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 31f27a6d2..ce8b1942b 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -415,7 +415,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx setState(ClientRoSessionState.OPEN); //Session persistence record shall be created after a peer had answered //the first (initial) request for that session - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); startSessionInactivityTimer(); } @@ -484,7 +484,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Action: Send RAA followed by CC update request, start Tx // New State: PENDING_U startTx(localEvent.getRequest().getMessage()); - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { startSessionInactivityTimer(); } setState(ClientRoSessionState.PENDING_UPDATE); @@ -517,7 +517,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // In all cases start Tx in order to assure failover startTx(localEvent.getRequest().getMessage()); - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { stopSessionInactivityTimer(); } setState(ClientRoSessionState.PENDING_TERMINATION); @@ -843,7 +843,7 @@ protected void setState(ClientRoSessionState newState, boolean release) { } stopTx(); - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { stopSessionInactivityTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); @@ -1363,7 +1363,7 @@ protected void handleRetransmission(Type eventType, IMessage msg, boolean tFlagS startFailoverStopTimer(); } - if (isSessionPersistenceEnabled()) { + if (sf.isSessionPersistenceEnabled()) { String oldPeer = flushSessionPersistenceContext(); logger.debug("Routing context for peer [{}] was removed from session [{}] due to retransmission", oldPeer, this.getSessionId()); } 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 index e270eab11..377dfa37d 100644 --- 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 @@ -60,6 +60,7 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); + //TODO [bk] to be removed - sesInactivityTimerVal sesInactivityTimerVal = sessionFactory.getContainer().getConfiguration().getIntValue(SessionTimeOut.ordinal(), (Integer) SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { @@ -67,15 +68,6 @@ public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFac } } - /** - * Tells whether session persistent routing is enabled for this session. - * - * @return true if enabled - */ - protected boolean isSessionPersistenceEnabled() { - return this.sessionPersistenceStorage != null; - } - /** * 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 @@ -129,6 +121,7 @@ protected String flushSessionPersistenceContext() { * Starts maximum session inactivity timer which defines how much time the persistence record * should be kept if there is no request sent within a session. */ + //TODO [bk] obsolete IDLE_SESSION_TIMER_NAME is started in Base session impl protected void startSessionInactivityTimer() { logger.debug("Scheduling session inactivity timer equal to [{}] ms", sesInactivityTimerVal); stopSessionInactivityTimer(); 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 87696a0ac..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 @@ -278,8 +278,14 @@ public AppSession getSession(String sessionId, Class aClas ClientCCASessionImpl clientSession = null; IClientCCASessionData data = (IClientCCASessionData) this.sessionDataFactory.getAppSessionData(ClientCCASession.class, sessionId); - clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), iss, 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 aC } IClientCCASessionData data = (IClientCCASessionData) this.sessionDataFactory.getAppSessionData(ClientCCASession.class, sessionId); data.setApplicationId(applicationId); - clientSession = new ClientCCASessionImpl(data, this.getMessageFactory(), iss, 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); From e94f2733c5c58be5391a721475af13d2988015f5 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 27 Jul 2017 15:51:27 +0200 Subject: [PATCH 17/26] fix to session inactivity timer --- .../java/org/jdiameter/api/BaseSession.java | 6 ++++- .../client/impl/BaseSessionImpl.java | 5 ++++ .../impl/app/AppRoutingAwareSessionImpl.java | 25 +++---------------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java index 572222746..cbb249c9b 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java @@ -42,7 +42,9 @@ package org.jdiameter.api; -/** + import java.io.Serializable; + + /** * The session delivery objects are responsible for delivering all incoming Message to a specific session. * It determines the Diameter Session object that the message belongs to by querying the message's session id AVP. * The delivery object searches the local session database for a matching session. If no matching session is found, @@ -105,5 +107,7 @@ public interface BaseSession { */ String getSessionId(); + Serializable getIdleSessionTimer(); + String IDLE_SESSION_TIMER_NAME = "IDLE_SESSION_TIMER"; } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java index da588a943..6137ff5fc 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java @@ -100,6 +100,11 @@ public abstract class BaseSessionImpl implements BaseSession { protected Serializable istTimerId; + @Override + public Serializable getIdleSessionTimer() { + return istTimerId; + } + @Override public long getCreationTime() { return creationTime; 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 index 377dfa37d..2f35a47c8 100644 --- 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 @@ -46,9 +46,6 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { private transient IPeerTable peerTable = null; private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null; - private final int sesInactivityTimerVal; - private Serializable sesInactivityTimerId = null; - /** * Parameterized constructor. If session persistence is supposed to be enabled, sessionStorage * argument should be of type {@link org.jdiameter.common.impl.data.RoutingAwareDataSource}. @@ -60,9 +57,6 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); - //TODO [bk] to be removed - sesInactivityTimerVal - sesInactivityTimerVal = sessionFactory.getContainer().getConfiguration().getIntValue(SessionTimeOut.ordinal(), (Integer) - SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; } @@ -117,25 +111,14 @@ protected String flushSessionPersistenceContext() { } } - /** - * Starts maximum session inactivity timer which defines how much time the persistence record - * should be kept if there is no request sent within a session. - */ - //TODO [bk] obsolete IDLE_SESSION_TIMER_NAME is started in Base session impl - protected void startSessionInactivityTimer() { - logger.debug("Scheduling session inactivity timer equal to [{}] ms", sesInactivityTimerVal); - stopSessionInactivityTimer(); - this.sesInactivityTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, sesInactivityTimerVal); - } - /** * Stops session inactivity timer. */ protected void stopSessionInactivityTimer() { - if (this.sesInactivityTimerId != null) { - logger.debug("Stopping session inactivity timer [{}]", this.sesInactivityTimerId); - timerFacility.cancel(this.sesInactivityTimerId); - this.sesInactivityTimerId = null; + Serializable idleSessionTimer = session.getIdleSessionTimer(); + if (idleSessionTimer != null) { + logger.debug("Stopping session inactivity timer [{}]", idleSessionTimer); + timerFacility.cancel(idleSessionTimer); } } From 84d264cb6328f6f3316c06d8c5daaf62d50a6961 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 27 Jul 2017 15:59:42 +0200 Subject: [PATCH 18/26] Revert "fix to session inactivity timer" This reverts commit e94f2733c5c58be5391a721475af13d2988015f5. --- .../java/org/jdiameter/api/BaseSession.java | 6 +---- .../client/impl/BaseSessionImpl.java | 5 ---- .../impl/app/AppRoutingAwareSessionImpl.java | 25 ++++++++++++++++--- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java index cbb249c9b..572222746 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/BaseSession.java @@ -42,9 +42,7 @@ package org.jdiameter.api; - import java.io.Serializable; - - /** +/** * The session delivery objects are responsible for delivering all incoming Message to a specific session. * It determines the Diameter Session object that the message belongs to by querying the message's session id AVP. * The delivery object searches the local session database for a matching session. If no matching session is found, @@ -107,7 +105,5 @@ public interface BaseSession { */ String getSessionId(); - Serializable getIdleSessionTimer(); - String IDLE_SESSION_TIMER_NAME = "IDLE_SESSION_TIMER"; } diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java index 6137ff5fc..da588a943 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/BaseSessionImpl.java @@ -100,11 +100,6 @@ public abstract class BaseSessionImpl implements BaseSession { protected Serializable istTimerId; - @Override - public Serializable getIdleSessionTimer() { - return istTimerId; - } - @Override public long getCreationTime() { return creationTime; 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 index 2f35a47c8..377dfa37d 100644 --- 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 @@ -46,6 +46,9 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { private transient IPeerTable peerTable = null; private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null; + private final int sesInactivityTimerVal; + private Serializable sesInactivityTimerId = null; + /** * Parameterized constructor. If session persistence is supposed to be enabled, sessionStorage * argument should be of type {@link org.jdiameter.common.impl.data.RoutingAwareDataSource}. @@ -57,6 +60,9 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); + //TODO [bk] to be removed - sesInactivityTimerVal + sesInactivityTimerVal = sessionFactory.getContainer().getConfiguration().getIntValue(SessionTimeOut.ordinal(), (Integer) + SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; } @@ -111,14 +117,25 @@ protected String flushSessionPersistenceContext() { } } + /** + * Starts maximum session inactivity timer which defines how much time the persistence record + * should be kept if there is no request sent within a session. + */ + //TODO [bk] obsolete IDLE_SESSION_TIMER_NAME is started in Base session impl + protected void startSessionInactivityTimer() { + logger.debug("Scheduling session inactivity timer equal to [{}] ms", sesInactivityTimerVal); + stopSessionInactivityTimer(); + this.sesInactivityTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, sesInactivityTimerVal); + } + /** * Stops session inactivity timer. */ protected void stopSessionInactivityTimer() { - Serializable idleSessionTimer = session.getIdleSessionTimer(); - if (idleSessionTimer != null) { - logger.debug("Stopping session inactivity timer [{}]", idleSessionTimer); - timerFacility.cancel(idleSessionTimer); + if (this.sesInactivityTimerId != null) { + logger.debug("Stopping session inactivity timer [{}]", this.sesInactivityTimerId); + timerFacility.cancel(this.sesInactivityTimerId); + this.sesInactivityTimerId = null; } } From 1e7f457acacf0ef25fcb8d6e93e022cb83c3469c Mon Sep 17 00:00:00 2001 From: Grzegorz Figiel Date: Fri, 28 Jul 2017 16:01:09 +0200 Subject: [PATCH 19/26] Inactive session timer refactoring into idle session timeout --- .../impl/app/cca/ClientCCASessionImpl.java | 10 +++---- .../impl/app/ro/ClientRoSessionImpl.java | 8 +++--- .../impl/app/AppRoutingAwareSessionImpl.java | 28 +++++++++---------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java index 4a7db3a58..8d8339995 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java @@ -382,7 +382,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx if (sf.isSessionPersistenceEnabled()) { initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); - startSessionInactivityTimer(); + startIdleSessionTimer(); } } else if (isProvisional(resultCode) || isFailure(resultCode)) { @@ -436,7 +436,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // New State: PENDING_U startTx((JCreditControlRequest) localEvent.getRequest()); if (sf.isSessionPersistenceEnabled()) { - startSessionInactivityTimer(); + startIdleSessionTimer(); } setState(ClientCCASessionState.PENDING_UPDATE); try { @@ -463,7 +463,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Action: Send CC termination request // New State: PENDING_T if (sf.isSessionPersistenceEnabled()) { - stopSessionInactivityTimer(); + stopIdleSessionTimerTimer(); } setState(ClientCCASessionState.PENDING_TERMINATION); try { @@ -700,7 +700,7 @@ protected void setState(ClientCCASessionState newState, boolean release) { stopTx(); if (sf.isSessionPersistenceEnabled()) { - stopSessionInactivityTimer(); + stopIdleSessionTimerTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); logger.debug("Session state reset, routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId()); @@ -1165,7 +1165,7 @@ else if (gatheredRequestedAction == REFUND_ACCOUNT) { // New State: PENDING_U context.grantAccessOnTxExpire(this); if (sf.isSessionPersistenceEnabled()) { - stopSessionInactivityTimer(); + stopIdleSessionTimerTimer(); } break; diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index ce8b1942b..3ead3e4e5 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -417,7 +417,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx //the first (initial) request for that session if (sf.isSessionPersistenceEnabled()) { initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); - startSessionInactivityTimer(); + startIdleSessionTimer(); } } else if (retrRequiredErrorCodes.contains(resultCode)) { @@ -485,7 +485,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // New State: PENDING_U startTx(localEvent.getRequest().getMessage()); if (sf.isSessionPersistenceEnabled()) { - startSessionInactivityTimer(); + startIdleSessionTimer(); } setState(ClientRoSessionState.PENDING_UPDATE); try { @@ -518,7 +518,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // In all cases start Tx in order to assure failover startTx(localEvent.getRequest().getMessage()); if (sf.isSessionPersistenceEnabled()) { - stopSessionInactivityTimer(); + stopIdleSessionTimerTimer(); } setState(ClientRoSessionState.PENDING_TERMINATION); try { @@ -844,7 +844,7 @@ protected void setState(ClientRoSessionState newState, boolean release) { stopTx(); if (sf.isSessionPersistenceEnabled()) { - stopSessionInactivityTimer(); + stopIdleSessionTimerTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); logger.debug("Session state reset, 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/AppRoutingAwareSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java index 377dfa37d..9075d6b1d 100644 --- 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 @@ -46,8 +46,8 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { private transient IPeerTable peerTable = null; private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null; - private final int sesInactivityTimerVal; - private Serializable sesInactivityTimerId = null; + private final int idleSessionTimeout; + private Serializable idleSessionTimerId = null; /** * Parameterized constructor. If session persistence is supposed to be enabled, sessionStorage @@ -60,8 +60,7 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); - //TODO [bk] to be removed - sesInactivityTimerVal - sesInactivityTimerVal = sessionFactory.getContainer().getConfiguration().getIntValue(SessionTimeOut.ordinal(), (Integer) + idleSessionTimeout = sessionFactory.getContainer().getConfiguration().getIntValue(SessionTimeOut.ordinal(), (Integer) SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; @@ -121,21 +120,20 @@ protected String flushSessionPersistenceContext() { * Starts maximum session inactivity timer which defines how much time the persistence record * should be kept if there is no request sent within a session. */ - //TODO [bk] obsolete IDLE_SESSION_TIMER_NAME is started in Base session impl - protected void startSessionInactivityTimer() { - logger.debug("Scheduling session inactivity timer equal to [{}] ms", sesInactivityTimerVal); - stopSessionInactivityTimer(); - this.sesInactivityTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, sesInactivityTimerVal); + protected void startIdleSessionTimer() { + logger.debug("Scheduling idle session (inactivity) timer equal to [{}] ms", idleSessionTimeout); + stopIdleSessionTimerTimer(); + this.idleSessionTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, idleSessionTimeout); } /** * Stops session inactivity timer. */ - protected void stopSessionInactivityTimer() { - if (this.sesInactivityTimerId != null) { - logger.debug("Stopping session inactivity timer [{}]", this.sesInactivityTimerId); - timerFacility.cancel(this.sesInactivityTimerId); - this.sesInactivityTimerId = null; + protected void stopIdleSessionTimerTimer() { + if (this.idleSessionTimerId != null) { + logger.debug("Stopping idle session (inactivity) timer [{}]", this.idleSessionTimerId); + timerFacility.cancel(this.idleSessionTimerId); + this.idleSessionTimerId = null; } } @@ -151,7 +149,7 @@ public void onTimer(String timerName) { checkIdleAppSession(); //no need to interfere with session state machine (simply remove routing context used for sticky sessions based routing) String oldPeer = flushSessionPersistenceContext(); - logger.debug("Session inactivity timer expired so routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId()); + logger.debug("Idle session (inactivity) timer expired so routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId()); } } } From 7f836abd4d76092e8350f767357ff8910f63b8bf Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Tue, 8 Aug 2017 14:08:55 +0200 Subject: [PATCH 20/26] fixed cast exception --- .../jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 9075d6b1d..1dabf9c80 100644 --- 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 @@ -46,7 +46,7 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { private transient IPeerTable peerTable = null; private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null; - private final int idleSessionTimeout; + private final long idleSessionTimeout; private Serializable idleSessionTimerId = null; /** @@ -60,7 +60,7 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); - idleSessionTimeout = sessionFactory.getContainer().getConfiguration().getIntValue(SessionTimeOut.ordinal(), (Integer) + idleSessionTimeout = sessionFactory.getContainer().getConfiguration().getLongValue(SessionTimeOut.ordinal(), (Long) SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; From 5a9c0213a698b4f8411d116d46efa6e7627520cb Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Tue, 8 Aug 2017 16:37:48 +0200 Subject: [PATCH 21/26] Get AVP index methods implemented --- .../main/java/org/jdiameter/api/AvpSet.java | 15 ++++++++++++++ .../client/impl/parser/AvpSetImpl.java | 20 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/core/jdiameter/api/src/main/java/org/jdiameter/api/AvpSet.java b/core/jdiameter/api/src/main/java/org/jdiameter/api/AvpSet.java index a2af490a8..d1eef3c31 100644 --- a/core/jdiameter/api/src/main/java/org/jdiameter/api/AvpSet.java +++ b/core/jdiameter/api/src/main/java/org/jdiameter/api/AvpSet.java @@ -94,6 +94,21 @@ public interface AvpSet extends Iterable, Serializable, Wrapper { */ AvpSet getAvps(int avpCode, long vendorId); + /** + * Get position of the first instance of the AVP + * @param avpCode code of the Avp + * @return index (position) of the first occurrence of the Avp. -1 in case Avp is not found + */ + int getAvpIndex(int avpCode); + + /** + * Get position of the first instance of the AVP + * @param avpCode code of the Avp + * @param vendorId vendorId of the Avp + * @return index (position) of the first occurrence of the Avp. -1 in case Avp is not found + */ + int getAvpIndex(int avpCode, long vendorId); + /** * Remove AVPs with avpCode * @param avpCode code of Avp diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/AvpSetImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/AvpSetImpl.java index 800fe3f5c..0155138ed 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/AvpSetImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/parser/AvpSetImpl.java @@ -119,8 +119,6 @@ public AvpSet getAvps(int avpCode) { return result; } - - @Override public AvpSet getAvps(int avpCode, long vendorId) { AvpSet result = new AvpSetImpl(); @@ -132,6 +130,24 @@ public AvpSet getAvps(int avpCode, long vendorId) { return result; } + public int getAvpIndex(int avpCode) { + for (Avp avp : this.avps) { + if (avp.getCode() == avpCode ) { + return this.avps.indexOf(avp); + } + } + return -1; + } + + public int getAvpIndex(int avpCode, long vendorId) { + for (Avp avp : this.avps) { + if (avp.getCode() == avpCode && avp.getVendorId() == vendorId) { + return this.avps.indexOf(avp); + } + } + return -1; + } + @Override public AvpSet removeAvp(int avpCode) { return removeAvp(avpCode, 0); From c5003b305c83c05a2acd223269a465a8fa29e343 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Thu, 10 Aug 2017 16:41:26 +0200 Subject: [PATCH 22/26] old timer commented --- .../impl/app/cca/ClientCCASessionImpl.java | 10 ++-- .../impl/app/ro/ClientRoSessionImpl.java | 8 ++-- .../impl/app/AppRoutingAwareSessionImpl.java | 48 +++++++++---------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java index 8d8339995..fbe5d146e 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java @@ -382,7 +382,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx if (sf.isSessionPersistenceEnabled()) { initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); - startIdleSessionTimer(); +// startIdleSessionTimer(); } } else if (isProvisional(resultCode) || isFailure(resultCode)) { @@ -436,7 +436,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // New State: PENDING_U startTx((JCreditControlRequest) localEvent.getRequest()); if (sf.isSessionPersistenceEnabled()) { - startIdleSessionTimer(); +// startIdleSessionTimer(); } setState(ClientCCASessionState.PENDING_UPDATE); try { @@ -463,7 +463,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Action: Send CC termination request // New State: PENDING_T if (sf.isSessionPersistenceEnabled()) { - stopIdleSessionTimerTimer(); +// stopIdleSessionTimerTimer(); } setState(ClientCCASessionState.PENDING_TERMINATION); try { @@ -700,7 +700,7 @@ protected void setState(ClientCCASessionState newState, boolean release) { stopTx(); if (sf.isSessionPersistenceEnabled()) { - stopIdleSessionTimerTimer(); +// stopIdleSessionTimerTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); logger.debug("Session state reset, routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId()); @@ -1165,7 +1165,7 @@ else if (gatheredRequestedAction == REFUND_ACCOUNT) { // New State: PENDING_U context.grantAccessOnTxExpire(this); if (sf.isSessionPersistenceEnabled()) { - stopIdleSessionTimerTimer(); +// stopIdleSessionTimerTimer(); } break; diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 3ead3e4e5..9fb5faeaf 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -417,7 +417,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx //the first (initial) request for that session if (sf.isSessionPersistenceEnabled()) { initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); - startIdleSessionTimer(); +// startIdleSessionTimer(); } } else if (retrRequiredErrorCodes.contains(resultCode)) { @@ -485,7 +485,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // New State: PENDING_U startTx(localEvent.getRequest().getMessage()); if (sf.isSessionPersistenceEnabled()) { - startIdleSessionTimer(); +// startIdleSessionTimer(); } setState(ClientRoSessionState.PENDING_UPDATE); try { @@ -518,7 +518,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // In all cases start Tx in order to assure failover startTx(localEvent.getRequest().getMessage()); if (sf.isSessionPersistenceEnabled()) { - stopIdleSessionTimerTimer(); +// stopIdleSessionTimerTimer(); } setState(ClientRoSessionState.PENDING_TERMINATION); try { @@ -844,7 +844,7 @@ protected void setState(ClientRoSessionState newState, boolean release) { stopTx(); if (sf.isSessionPersistenceEnabled()) { - stopIdleSessionTimerTimer(); +// stopIdleSessionTimerTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); logger.debug("Session state reset, 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/AppRoutingAwareSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java index 1dabf9c80..1ab607491 100644 --- 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 @@ -32,7 +32,7 @@ import java.io.Serializable; -import static org.jdiameter.client.impl.helpers.Parameters.SessionTimeOut; +//import static org.jdiameter.client.impl.helpers.Parameters.SessionTimeOut; /** * Routing aware extension of {@link AppSessionImpl} that enables proper diameter session @@ -46,7 +46,7 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { private transient IPeerTable peerTable = null; private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null; - private final long idleSessionTimeout; +// private final long idleSessionTimeout; private Serializable idleSessionTimerId = null; /** @@ -60,8 +60,8 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); - idleSessionTimeout = sessionFactory.getContainer().getConfiguration().getLongValue(SessionTimeOut.ordinal(), (Long) - SessionTimeOut.defValue()) * 1000; +// idleSessionTimeout = sessionFactory.getContainer().getConfiguration().getLongValue(SessionTimeOut.ordinal(), (Long) +// SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; } @@ -116,26 +116,26 @@ protected String flushSessionPersistenceContext() { } } - /** - * Starts maximum session inactivity timer which defines how much time the persistence record - * should be kept if there is no request sent within a session. - */ - protected void startIdleSessionTimer() { - logger.debug("Scheduling idle session (inactivity) timer equal to [{}] ms", idleSessionTimeout); - stopIdleSessionTimerTimer(); - this.idleSessionTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, idleSessionTimeout); - } - - /** - * Stops session inactivity timer. - */ - protected void stopIdleSessionTimerTimer() { - if (this.idleSessionTimerId != null) { - logger.debug("Stopping idle session (inactivity) timer [{}]", this.idleSessionTimerId); - timerFacility.cancel(this.idleSessionTimerId); - this.idleSessionTimerId = null; - } - } +// /** +// * Starts maximum session inactivity timer which defines how much time the persistence record +// * should be kept if there is no request sent within a session. +// */ +// protected void startIdleSessionTimer() { +// logger.debug("Scheduling idle session (inactivity) timer equal to [{}] ms", idleSessionTimeout); +// stopIdleSessionTimerTimer(); +// this.idleSessionTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, idleSessionTimeout); +// } +// +// /** +// * Stops session inactivity timer. +// */ +// protected void stopIdleSessionTimerTimer() { +// if (this.idleSessionTimerId != null) { +// logger.debug("Stopping idle session (inactivity) timer [{}]", this.idleSessionTimerId); +// timerFacility.cancel(this.idleSessionTimerId); +// this.idleSessionTimerId = null; +// } +// } /** * Handles expiry of session inactivity timer. Should be called by any subclasses which define From 0dd40cdae34ae15270b9c7053bd39a0b8859be0f Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Fri, 18 Aug 2017 10:30:24 +0200 Subject: [PATCH 23/26] moved constants from IMessage to IRoMessageFactory --- .../main/java/org/jdiameter/client/api/IMessage.java | 10 ---------- .../client/impl/app/ro/ClientRoSessionImpl.java | 8 ++++---- .../jdiameter/common/api/app/ro/IRoMessageFactory.java | 10 ++++++++++ .../common/impl/app/ro/RoSessionFactoryImpl.java | 3 +-- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java index 4800749ef..5bbee0696 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/api/IMessage.java @@ -62,16 +62,6 @@ */ public interface IMessage extends IRequest, IAnswer { - /** - * 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; - /** * The message is not sent to the network */ diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 9fb5faeaf..9e662bddb 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -370,7 +370,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx setState(ClientRoSessionState.PENDING_INITIAL); // RFC 4006: For new credit-control sessions, failover to an alternative // credit-control server SHOULD be performed if possible. - sessionData.setGatheredCCSF(IMessage.SESSION_FAILOVER_SUPPORTED_VALUE); + sessionData.setGatheredCCSF(IRoMessageFactory.SESSION_FAILOVER_SUPPORTED_VALUE); try { dispatchEvent(localEvent.getRequest()); } @@ -394,7 +394,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx case RECEIVED_INITIAL_ANSWER: Message message = localEvent.getAnswer().getMessage(); - int ccSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + int ccSessionFailover = IRoMessageFactory.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; Avp avpCcSessionFailover = message.getAvps().getAvp(Avp.CC_SESSION_FAILOVER); if (avpCcSessionFailover != null) { @@ -555,7 +555,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { case RECEIVED_UPDATE_ANSWER: Message message = localEvent.getAnswer().getMessage(); - int ccSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + int ccSessionFailover = IRoMessageFactory.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; Avp avpCcSessionFailover = message.getAvps().getAvp(Avp.CC_SESSION_FAILOVER); if (avpCcSessionFailover != null) { @@ -659,7 +659,7 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { //FIXME: Alex broke this, setting back "true" ? //setState(ClientRoSessionState.IDLE, false); Message message = localEvent.getAnswer().getMessage(); - int ccSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + int ccSessionFailover = IRoMessageFactory.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; Avp avpCcSessionFailover = message.getAvps().getAvp(Avp.CC_SESSION_FAILOVER); if (avpCcSessionFailover != null) { 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/impl/app/ro/RoSessionFactoryImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/ro/RoSessionFactoryImpl.java index a2e1888cc..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 @@ -41,7 +41,6 @@ import org.jdiameter.api.ro.ServerRoSessionListener; import org.jdiameter.api.ro.events.RoCreditControlAnswer; import org.jdiameter.api.ro.events.RoCreditControlRequest; -import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.ISessionFactory; import org.jdiameter.client.impl.app.ro.ClientRoSessionImpl; import org.jdiameter.client.impl.app.ro.IClientRoSessionData; @@ -72,7 +71,7 @@ public class RoSessionFactoryImpl implements IRoSessionFactory, ClientRoSessionL // Message timeout value (in milliseconds) protected int defaultDirectDebitingFailureHandling = 0; protected int defaultCreditControlFailureHandling = 0; - protected int defaultCreditControlSessionFailover = IMessage.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; + protected int defaultCreditControlSessionFailover = IRoMessageFactory.SESSION_FAILOVER_NOT_SUPPORTED_VALUE; // its seconds protected long defaultValidityTime = 60; From 4204f5b8e4049675132a9c9105fdcbba93c2d1df Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Fri, 18 Aug 2017 10:55:02 +0200 Subject: [PATCH 24/26] old timer deleted --- .../impl/app/cca/ClientCCASessionImpl.java | 12 -------- .../impl/app/ro/ClientRoSessionImpl.java | 8 ----- .../impl/app/AppRoutingAwareSessionImpl.java | 30 ------------------- 3 files changed, 50 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java index fbe5d146e..3185312f1 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/cca/ClientCCASessionImpl.java @@ -380,9 +380,7 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx //Session persistence record shall be created after a peer had answered the //first (initial) request for that session if (sf.isSessionPersistenceEnabled()) { - initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); -// startIdleSessionTimer(); } } else if (isProvisional(resultCode) || isFailure(resultCode)) { @@ -435,9 +433,6 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Action: Send RAA followed by CC update request, start Tx // New State: PENDING_U startTx((JCreditControlRequest) localEvent.getRequest()); - if (sf.isSessionPersistenceEnabled()) { -// startIdleSessionTimer(); - } setState(ClientCCASessionState.PENDING_UPDATE); try { dispatchEvent(localEvent.getRequest()); @@ -462,9 +457,6 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Event: User service terminated // Action: Send CC termination request // New State: PENDING_T - if (sf.isSessionPersistenceEnabled()) { -// stopIdleSessionTimerTimer(); - } setState(ClientCCASessionState.PENDING_TERMINATION); try { dispatchEvent(localEvent.getRequest()); @@ -700,7 +692,6 @@ protected void setState(ClientCCASessionState newState, boolean release) { stopTx(); if (sf.isSessionPersistenceEnabled()) { -// stopIdleSessionTimerTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); logger.debug("Session state reset, routing context for peer [{}] was removed from session [{}]", oldPeer, this.getSessionId()); @@ -1164,9 +1155,6 @@ else if (gatheredRequestedAction == REFUND_ACCOUNT) { // Action: Grant service to end user // New State: PENDING_U context.grantAccessOnTxExpire(this); - if (sf.isSessionPersistenceEnabled()) { -// stopIdleSessionTimerTimer(); - } break; case CCFH_TERMINATE: diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java index 9e662bddb..b8139f9e2 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/app/ro/ClientRoSessionImpl.java @@ -417,7 +417,6 @@ protected boolean handleEventForSessionBased(StateEvent event) throws InternalEx //the first (initial) request for that session if (sf.isSessionPersistenceEnabled()) { initSessionPersistenceContext(localEvent.getRequest(), localEvent.getAnswer()); -// startIdleSessionTimer(); } } else if (retrRequiredErrorCodes.contains(resultCode)) { @@ -484,9 +483,6 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // Action: Send RAA followed by CC update request, start Tx // New State: PENDING_U startTx(localEvent.getRequest().getMessage()); - if (sf.isSessionPersistenceEnabled()) { -// startIdleSessionTimer(); - } setState(ClientRoSessionState.PENDING_UPDATE); try { dispatchEvent(localEvent.getRequest()); @@ -517,9 +513,6 @@ else if (isProvisional(resultCode) || isFailure(resultCode)) { // In all cases start Tx in order to assure failover startTx(localEvent.getRequest().getMessage()); - if (sf.isSessionPersistenceEnabled()) { -// stopIdleSessionTimerTimer(); - } setState(ClientRoSessionState.PENDING_TERMINATION); try { dispatchEvent(localEvent.getRequest()); @@ -844,7 +837,6 @@ protected void setState(ClientRoSessionState newState, boolean release) { stopTx(); if (sf.isSessionPersistenceEnabled()) { -// stopIdleSessionTimerTimer(); if (!release) { String oldPeer = flushSessionPersistenceContext(); logger.debug("Session state reset, 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/AppRoutingAwareSessionImpl.java b/core/jdiameter/impl/src/main/java/org/jdiameter/common/impl/app/AppRoutingAwareSessionImpl.java index 1ab607491..c4d74ffb2 100644 --- 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 @@ -30,10 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.Serializable; - -//import static org.jdiameter.client.impl.helpers.Parameters.SessionTimeOut; - /** * Routing aware extension of {@link AppSessionImpl} that enables proper diameter session * load balancing. It provides diameter session persistence which maps a single diameter @@ -46,9 +42,6 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { private transient IPeerTable peerTable = null; private transient IRoutingAwareSessionDatasource sessionPersistenceStorage = null; -// private final long idleSessionTimeout; - private Serializable idleSessionTimerId = null; - /** * Parameterized constructor. If session persistence is supposed to be enabled, sessionStorage * argument should be of type {@link org.jdiameter.common.impl.data.RoutingAwareDataSource}. @@ -60,8 +53,6 @@ public abstract class AppRoutingAwareSessionImpl extends AppSessionImpl { public AppRoutingAwareSessionImpl(ISessionDatasource sessionStorage, ISessionFactory sessionFactory, IAppSessionData appSessionData) { super(sessionFactory, appSessionData); peerTable = sessionFactory.getContainer().getAssemblerFacility().getComponentInstance(IPeerTable.class); -// idleSessionTimeout = sessionFactory.getContainer().getConfiguration().getLongValue(SessionTimeOut.ordinal(), (Long) -// SessionTimeOut.defValue()) * 1000; if (sessionStorage instanceof IRoutingAwareSessionDatasource) { sessionPersistenceStorage = (IRoutingAwareSessionDatasource) sessionStorage; } @@ -116,27 +107,6 @@ protected String flushSessionPersistenceContext() { } } -// /** -// * Starts maximum session inactivity timer which defines how much time the persistence record -// * should be kept if there is no request sent within a session. -// */ -// protected void startIdleSessionTimer() { -// logger.debug("Scheduling idle session (inactivity) timer equal to [{}] ms", idleSessionTimeout); -// stopIdleSessionTimerTimer(); -// this.idleSessionTimerId = this.timerFacility.schedule(this.getSessionId(), IDLE_SESSION_TIMER_NAME, idleSessionTimeout); -// } -// -// /** -// * Stops session inactivity timer. -// */ -// protected void stopIdleSessionTimerTimer() { -// if (this.idleSessionTimerId != null) { -// logger.debug("Stopping idle session (inactivity) timer [{}]", this.idleSessionTimerId); -// timerFacility.cancel(this.idleSessionTimerId); -// this.idleSessionTimerId = null; -// } -// } - /** * Handles expiry of session inactivity timer. Should be called by any subclasses which define * any additional timers. From 36a739dfc44dd89de60becd02f3552ec423dabbe Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Tue, 29 Aug 2017 13:17:14 +0200 Subject: [PATCH 25/26] removed session inactivity timeout, config for jdiameter updated --- .../org/jdiameter/client/impl/helpers/Parameters.java | 7 ------- .../client/impl/helpers/XMLConfiguration.java | 4 ---- .../server/impl/helpers/XMLConfiguration.java | 4 ---- .../src/main/resources/META-INF/jdiameter-client.xsd | 8 -------- .../src/main/resources/META-INF/jdiameter-server.xsd | 11 ++--------- .../config/jdiameter-config_ext_routing_failover.xml | 6 +++--- .../diameter/stack/DiameterStackMultiplexer.java | 5 ----- .../diameter/stack/DiameterStackMultiplexerMBean.java | 10 ---------- .../diameter/stack/management/Parameters.java | 4 ---- .../diameter/stack/management/ParametersImpl.java | 11 ----------- 10 files changed, 5 insertions(+), 65 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java index c1a654064..4651c7c8a 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java @@ -402,13 +402,6 @@ public class Parameters extends Ordinal { */ public static final Parameters DictionaryReceiveLevel = new Parameters("DictionaryReceiveLevel", String.class, "OFF"); - /** - * Maximum session inactivity time specified in seconds which defines how much time - * the persistence record should be kept if there is no request sent within a session. - * Irrelevant when session persistent routing is not enabled. - */ - public static final Parameters SessionInactivityTimeOut = new Parameters("SessionInactivityTimeOut", Integer.class, 600); - /** * Tx timer as described in chapter 13. of RFC 4006: *

The Tx timer is introduced to control the waiting time in the client in the Pending state. The recommended value is 10 seconds.
diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java index f43c64500..51ff71e7e 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java @@ -110,7 +110,6 @@ 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.SessionInactivityTimeOut; 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; @@ -381,9 +380,6 @@ else if (nodeName.equals("Concurrent")) { else if (nodeName.equals("Dictionary")) { addDictionary(Dictionary, c.item(i)); } - else if (nodeName.equals("SessionInactivityTimeOut")) { - add(SessionInactivityTimeOut, getIntValue(c.item(i))); - } else if (nodeName.equals("TxTimeOut")) { add(TxTimeOut, getLongValue(c.item(i))); } 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 844646232..0cf764913 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 @@ -111,7 +111,6 @@ 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.SessionInactivityTimeOut; 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; @@ -393,9 +392,6 @@ else if (nodeName.equals("Dictionary")) { else if (nodeName.equals("RequestTable")) { addRequestTable(RequestTable, c.item(i)); } - else if (nodeName.equals("SessionInactivityTimeOut")) { - add(SessionInactivityTimeOut, getIntValue(c.item(i))); - } else if (nodeName.equals("TxTimeOut")) { add(TxTimeOut, getLongValue(c.item(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 ed1106de7..1d59c864c 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 @@ -247,14 +247,6 @@ - - - Session inactivity timeout in seconds used for session persistence. - - - - - 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 0b52a0af8..89d7138d1 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 @@ - + + @@ -312,14 +313,6 @@ - - - Session inactivity timeout in seconds used for session persistence. - - - - - Server Socket bind delay in milliseconds. diff --git a/core/mux/common/config/jdiameter-config_ext_routing_failover.xml b/core/mux/common/config/jdiameter-config_ext_routing_failover.xml index 18851ea6d..0be6654c4 100644 --- a/core/mux/common/config/jdiameter-config_ext_routing_failover.xml +++ b/core/mux/common/config/jdiameter-config_ext_routing_failover.xml @@ -31,15 +31,15 @@ + - - - + + 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 fc460b0ba..053bcfbf0 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 @@ -60,7 +60,6 @@ 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.RetransmissionTimeOut; -import static org.jdiameter.client.impl.helpers.Parameters.SessionInactivityTimeOut; 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; @@ -855,10 +854,6 @@ public void _Parameters_setRecTimeout(long stopTimeout) throws MBeanException { getMutableConfiguration().setLongValue(RecTimeOut.ordinal(), stopTimeout); } - public void _Parameters_setSessionInactivityTimeout(int timeout) throws MBeanException { - getMutableConfiguration().setIntValue(SessionInactivityTimeOut.ordinal(), timeout); - } - public void _Parameters_setTxTimeout(long txTimeout) throws MBeanException { getMutableConfiguration().setLongValue(TxTimeOut.ordinal(), txTimeout); } 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 6bfacc522..4a9a7bee9 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,16 +207,6 @@ public interface DiameterStackMultiplexerMBean extends ServiceMBean { */ void _Parameters_setRecTimeout(long recTimeout) throws MBeanException; - /** - * Sets the timeout value for session inactivity timer which defines how much time - * the persistence record should be kept if there is no request sent within a session. - * Irrelevant when session persistent routing is not enabled, defaults to 1800 seconds. - * - * @param timeout the amount of time, in seconds. - * @throws MBeanException if the operation is unable to perform correctly - */ - void _Parameters_setSessionInactivityTimeout(int timeout) throws MBeanException; - /** * Sets the waiting time in the client in the Pending state. (default: 10000, 10 seconds). * 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 9ffd7470e..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,10 +95,6 @@ public interface Parameters extends Serializable { void setRecTimeout(long recTimeout); - int getSessionInactivityTimeout(); - - void setSessionInactivityTimeout(long sessionInactivityTimeout); - long getTxTimeout(); void setTxTimeout(long txTimeout); 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 aceccced1..8d2adf8c9 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 @@ -55,7 +55,6 @@ 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.RetransmissionTimeOut; -import static org.jdiameter.client.impl.helpers.Parameters.SessionInactivityTimeOut; 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; @@ -101,7 +100,6 @@ public class ParametersImpl implements Parameters { private long txTimeout; private long retransmissionTimeOut; private String retransmissionRequiredResCodes; - private int sessionInactivityTimeout; // Gone since merge with build-350 // private String threadPool_Priority; @@ -131,7 +129,6 @@ public ParametersImpl(MutableConfiguration config) { this.txTimeout = config.getLongValue(TxTimeOut.ordinal(), 10000); this.retransmissionTimeOut = config.getLongValue(RetransmissionTimeOut.ordinal(), 45000L); this.retransmissionRequiredResCodes = Arrays.toString(config.getIntArrayValue(RetransmissionRequiredResCodes.ordinal(), null)); - this.sessionInactivityTimeout = config.getIntValue(SessionInactivityTimeOut.ordinal(), 600); // Concurrent Entities for (Configuration concurrentEntity : config.getChildren(Concurrent.ordinal())) { @@ -266,14 +263,6 @@ public void setRecTimeout(long recTimeout) { DiameterConfiguration.getMutableConfiguration().setLongValue(RecTimeOut.ordinal(), recTimeout); } - public int getSessionInactivityTimeout() { - return sessionInactivityTimeout; - } - - public void setSessionInactivityTimeout(long sessionInactivityTimeout) { - DiameterConfiguration.getMutableConfiguration().setLongValue(SessionInactivityTimeOut.ordinal(), sessionInactivityTimeout); - } - public long getTxTimeout() { return txTimeout; } From 7eac72c8e5e20f141ec97a30d3b971aab05f4c82 Mon Sep 17 00:00:00 2001 From: Bartosz Krok Date: Tue, 29 Aug 2017 13:22:23 +0200 Subject: [PATCH 26/26] removed retransmission timeout --- .../org/jdiameter/client/impl/helpers/Parameters.java | 6 ------ .../client/impl/helpers/XMLConfiguration.java | 4 ---- .../server/impl/helpers/XMLConfiguration.java | 4 ---- .../src/main/resources/META-INF/jdiameter-client.xsd | 8 -------- .../src/main/resources/META-INF/jdiameter-server.xsd | 8 -------- .../diameter/stack/DiameterStackMultiplexer.java | 5 ----- .../diameter/stack/DiameterStackMultiplexerMBean.java | 10 ---------- .../diameter/stack/management/ParametersImpl.java | 11 ----------- 8 files changed, 56 deletions(-) diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java index 4651c7c8a..e46ebf0c4 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/Parameters.java @@ -408,12 +408,6 @@ public class Parameters extends Ordinal { */ public static final Parameters TxTimeOut = new Parameters("TxTimeOut", Long.class, 10000L); - /** - * Retransmission stop timer which defines how long the stack should wait for the answer message from remote peers and carry on with - * retransmissions in case of delivery failures. - */ - public static final Parameters RetransmissionTimeOut = new Parameters("RetransmissionTimeOut", Long.class, 45000L); - /** * Array of result codes which make an initial request to be retransmitted to another remote peer. */ diff --git a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java index 51ff71e7e..3c760cf1b 100644 --- a/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java +++ b/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/helpers/XMLConfiguration.java @@ -132,7 +132,6 @@ import static org.jdiameter.server.impl.helpers.Parameters.RealmHosts; import static org.jdiameter.server.impl.helpers.Parameters.RealmLocalAction; import static org.jdiameter.server.impl.helpers.Parameters.RealmName; -import static org.jdiameter.server.impl.helpers.Parameters.RetransmissionTimeOut; import java.io.File; import java.io.InputStream; @@ -383,9 +382,6 @@ else if (nodeName.equals("Dictionary")) { else if (nodeName.equals("TxTimeOut")) { add(TxTimeOut, getLongValue(c.item(i))); } - else if (nodeName.equals("RetransmissionTimeOut")) { - add(RetransmissionTimeOut, getLongValue(c.item(i))); - } else if (nodeName.equals("RetransmissionRequiredResCodes")) { addRetransmissionRequiredResCodes(c.item(i)); } 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 0cf764913..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 @@ -104,7 +104,6 @@ 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.RetransmissionTimeOut; 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; @@ -395,9 +394,6 @@ else if (nodeName.equals("RequestTable")) { else if (nodeName.equals("TxTimeOut")) { add(TxTimeOut, getLongValue(c.item(i))); } - else if (nodeName.equals("RetransmissionTimeOut")) { - add(RetransmissionTimeOut, getLongValue(c.item(i))); - } else if (nodeName.equals("RetransmissionRequiredResCodes")) { addRetransmissionRequiredResCodes(c.item(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 1d59c864c..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 @@ -231,14 +231,6 @@ - - - Retransmission stop timer which defines how long the stack should carry on with retransmissions in case of delivery failures. - - - - - Comma delimited list of result codes which make an initial request to be retransmitted. 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 89d7138d1..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 @@ -297,14 +297,6 @@ - - - Retransmission stop timer which defines how long the stack should carry on with retransmissions in case of delivery failures. - - - - - Comma delimited list of result codes which make an initial request to be retransmitted. 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 053bcfbf0..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 @@ -59,7 +59,6 @@ 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.RetransmissionTimeOut; 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; @@ -858,10 +857,6 @@ public void _Parameters_setTxTimeout(long txTimeout) throws MBeanException { getMutableConfiguration().setLongValue(TxTimeOut.ordinal(), txTimeout); } - public void _Parameters_setRetransmissionTimeout(long retransmissionTimeout) throws MBeanException { - getMutableConfiguration().setLongValue(RetransmissionTimeOut.ordinal(), retransmissionTimeout); - } - public void _Parameters_setRetransmissionRequiredResCodes(String resCodes) throws MBeanException { if(resCodes != null && resCodes.length() > 0) { String[] codesArray = resCodes.replaceAll(" ", "").split(","); 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 4a9a7bee9..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 @@ -215,16 +215,6 @@ public interface DiameterStackMultiplexerMBean extends ServiceMBean { */ void _Parameters_setTxTimeout(long txTimeout) throws MBeanException; - /** - * Defines one of failover algorithm stop conditions. Namely, in case of consecutive peers - * failures the failover algorithm will try to retransmit a given message to other peers - * until retransmission timeout expires - * - * @param retransmissionTimeout the amount of time, in ms. - * @throws MBeanException if the operation is unable to perform correctly - */ - void _Parameters_setRetransmissionTimeout(long retransmissionTimeout) throws MBeanException; - /** * Defines a list of result codes which make an initial request to be retransmitted to * another remote peer. 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 8d2adf8c9..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 @@ -54,7 +54,6 @@ 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.RetransmissionTimeOut; 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; @@ -98,7 +97,6 @@ public class ParametersImpl implements Parameters { private long dpaTimeout; private long recTimeout; private long txTimeout; - private long retransmissionTimeOut; private String retransmissionRequiredResCodes; // Gone since merge with build-350 @@ -127,7 +125,6 @@ public ParametersImpl(MutableConfiguration config) { this.dpaTimeout = config.getLongValue(DpaTimeOut.ordinal(), 5000L); this.recTimeout = config.getLongValue(RecTimeOut.ordinal(), 10000L); this.txTimeout = config.getLongValue(TxTimeOut.ordinal(), 10000); - this.retransmissionTimeOut = config.getLongValue(RetransmissionTimeOut.ordinal(), 45000L); this.retransmissionRequiredResCodes = Arrays.toString(config.getIntArrayValue(RetransmissionRequiredResCodes.ordinal(), null)); // Concurrent Entities @@ -271,14 +268,6 @@ public void setTxTimeout(long txTimeout) { DiameterConfiguration.getMutableConfiguration().setLongValue(TxTimeOut.ordinal(), txTimeout); } - public long getRetransmissionTimeout() { - return retransmissionTimeOut; - } - - public void setRetransmissionTimeout(long retrTimeout) { - DiameterConfiguration.getMutableConfiguration().setLongValue(RetransmissionTimeOut.ordinal(), retrTimeout); - } - public String getRetransmissionRequiredResCodes() { return retransmissionRequiredResCodes; }