/* * Mobicents, Communications Middleware * * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Middleware LLC. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * 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 Lesser General Public License * for more details. * * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * * Boston, MA 02110-1301 USA */ package org.mobicents.slee.resource.diameter.base; import net.java.slee.resource.diameter.base.DiameterMessageFactory; import net.java.slee.resource.diameter.base.events.AbortSessionAnswer; import net.java.slee.resource.diameter.base.events.AbortSessionRequest; import net.java.slee.resource.diameter.base.events.AccountingAnswer; import net.java.slee.resource.diameter.base.events.AccountingRequest; import net.java.slee.resource.diameter.base.events.CapabilitiesExchangeAnswer; import net.java.slee.resource.diameter.base.events.CapabilitiesExchangeRequest; import net.java.slee.resource.diameter.base.events.DeviceWatchdogAnswer; import net.java.slee.resource.diameter.base.events.DeviceWatchdogRequest; import net.java.slee.resource.diameter.base.events.DiameterCommand; import net.java.slee.resource.diameter.base.events.DiameterHeader; import net.java.slee.resource.diameter.base.events.DiameterMessage; import net.java.slee.resource.diameter.base.events.DisconnectPeerAnswer; import net.java.slee.resource.diameter.base.events.DisconnectPeerRequest; import net.java.slee.resource.diameter.base.events.ExtensionDiameterMessage; import net.java.slee.resource.diameter.base.events.ReAuthAnswer; import net.java.slee.resource.diameter.base.events.ReAuthRequest; import net.java.slee.resource.diameter.base.events.SessionTerminationAnswer; import net.java.slee.resource.diameter.base.events.SessionTerminationRequest; import net.java.slee.resource.diameter.base.events.avp.AvpNotAllowedException; import net.java.slee.resource.diameter.base.events.avp.DiameterAvp; import net.java.slee.resource.diameter.base.events.avp.DiameterAvpCodes; import net.java.slee.resource.diameter.base.events.avp.DiameterIdentity; import net.java.slee.resource.diameter.base.events.avp.GroupedAvp; import org.apache.log4j.Logger; import org.jdiameter.api.ApplicationId; import org.jdiameter.api.AvpSet; import org.jdiameter.api.Message; import org.jdiameter.api.Session; import org.jdiameter.api.Stack; import org.jdiameter.client.impl.helpers.UIDGenerator; import org.jdiameter.client.impl.parser.MessageImpl; import org.mobicents.slee.resource.diameter.base.events.AbortSessionAnswerImpl; import org.mobicents.slee.resource.diameter.base.events.AbortSessionRequestImpl; import org.mobicents.slee.resource.diameter.base.events.AccountingAnswerImpl; import org.mobicents.slee.resource.diameter.base.events.AccountingRequestImpl; import org.mobicents.slee.resource.diameter.base.events.CapabilitiesExchangeAnswerImpl; import org.mobicents.slee.resource.diameter.base.events.CapabilitiesExchangeRequestImpl; import org.mobicents.slee.resource.diameter.base.events.DeviceWatchdogAnswerImpl; import org.mobicents.slee.resource.diameter.base.events.DeviceWatchdogRequestImpl; import org.mobicents.slee.resource.diameter.base.events.DisconnectPeerAnswerImpl; import org.mobicents.slee.resource.diameter.base.events.DisconnectPeerRequestImpl; import org.mobicents.slee.resource.diameter.base.events.ExtensionDiameterMessageImpl; import org.mobicents.slee.resource.diameter.base.events.ReAuthAnswerImpl; import org.mobicents.slee.resource.diameter.base.events.ReAuthRequestImpl; import org.mobicents.slee.resource.diameter.base.events.SessionTerminationAnswerImpl; import org.mobicents.slee.resource.diameter.base.events.SessionTerminationRequestImpl; /** * Diameter Base Message Factory * * <br> * Super project: mobicents <br> * 6:52:13 PM May 9, 2008 <br> * * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a> * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a> * @author Erick Svenson */ public class DiameterMessageFactoryImpl implements DiameterMessageFactory { private static Logger logger = Logger.getLogger(DiameterMessageFactoryImpl.class); // Used for generating session id's public static final UIDGenerator uid = new UIDGenerator(); protected Session session; protected Stack stack; ApplicationId baseAuthAppId = ApplicationId.createByAuthAppId(0, 0); ApplicationId baseAcctAppId = ApplicationId.createByAccAppId(0, 0); public DiameterMessageFactoryImpl(Session session, Stack stack, DiameterIdentity... avps) { this.session = session; this.stack = stack; } public DiameterMessageFactoryImpl(Stack stack) { this.stack = stack; } public AbortSessionAnswer createAbortSessionAnswer(AbortSessionRequest request, DiameterAvp[] avps) throws AvpNotAllowedException { AbortSessionAnswer msg = (AbortSessionAnswer) this.createDiameterMessage(request.getHeader(), avps, Message.ABORT_SESSION_ANSWER, getApplicationId(request)); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public AbortSessionAnswer createAbortSessionAnswer(AbortSessionRequest request) { try { return createAbortSessionAnswer(request, new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create ASA message.", e); } return null; } public AbortSessionRequest createAbortSessionRequest(DiameterAvp[] avps) throws AvpNotAllowedException { AbortSessionRequest msg = (AbortSessionRequest) this.createDiameterMessage(null, avps, Message.ABORT_SESSION_REQUEST, baseAuthAppId); if(!msg.hasSessionId() && session!=null) { msg.setSessionId(session.getSessionId()); } return msg; } public AbortSessionRequest createAbortSessionRequest() { try { return createAbortSessionRequest(new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create ASR message.", e); } return null; } public AccountingAnswer createAccountingAnswer(AccountingRequest request, DiameterAvp[] avps) throws AvpNotAllowedException { AccountingAnswer msg = (AccountingAnswer) this.createDiameterMessage(request.getHeader(), avps, Message.ACCOUNTING_ANSWER, getApplicationId(request)); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public AccountingAnswer createAccountingAnswer(AccountingRequest request) { try { return createAccountingAnswer(request, new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create ACA message.", e); } return null; } public AccountingRequest createAccountingRequest(DiameterAvp[] avps) throws AvpNotAllowedException { AccountingRequest msg = (AccountingRequest) this.createDiameterMessage(null, avps, Message.ACCOUNTING_REQUEST, baseAcctAppId); if(!msg.hasSessionId() && session!=null) { msg.setSessionId(session.getSessionId()); } return msg; } public AccountingRequest createAccountingRequest() { try { return createAccountingRequest(new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create ACR message.", e); } return null; } public CapabilitiesExchangeAnswer createCapabilitiesExchangeAnswer(CapabilitiesExchangeRequest request, DiameterAvp[] avps) throws AvpNotAllowedException { CapabilitiesExchangeAnswer msg = (CapabilitiesExchangeAnswer) this.createDiameterMessage(request.getHeader(), avps, Message.CAPABILITIES_EXCHANGE_ANSWER, getApplicationId(request)); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public CapabilitiesExchangeAnswer createCapabilitiesExchangeAnswer(CapabilitiesExchangeRequest request) { try { return createCapabilitiesExchangeAnswer(request, new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create CEA message.", e); } return null; } public CapabilitiesExchangeRequest createCapabilitiesExchangeRequest(DiameterAvp[] avps) throws AvpNotAllowedException { // FIXME: Alexandre: CER should be able to have both Auth and Acct App-Id... CapabilitiesExchangeRequest msg = (CapabilitiesExchangeRequest) this.createDiameterMessage(null, avps, Message.CAPABILITIES_EXCHANGE_REQUEST, baseAcctAppId); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public CapabilitiesExchangeRequest createCapabilitiesExchangeRequest() { try { return createCapabilitiesExchangeRequest(new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create CER message.", e); } return null; } public DeviceWatchdogAnswer createDeviceWatchdogAnswer(DeviceWatchdogRequest request, DiameterAvp[] avps) throws AvpNotAllowedException { DeviceWatchdogAnswer msg = (DeviceWatchdogAnswer) this.createDiameterMessage(request.getHeader(), avps, Message.DEVICE_WATCHDOG_ANSWER, getApplicationId(request)); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public DeviceWatchdogAnswer createDeviceWatchdogAnswer(DeviceWatchdogRequest request) { try { return createDeviceWatchdogAnswer(request, new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create DWA message.", e); } return null; } public DeviceWatchdogRequest createDeviceWatchdogRequest(DiameterAvp[] avps) throws AvpNotAllowedException { DeviceWatchdogRequest msg = (DeviceWatchdogRequest) this.createDiameterMessage(null, avps, Message.DEVICE_WATCHDOG_REQUEST, baseAuthAppId); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public DeviceWatchdogRequest createDeviceWatchdogRequest() { try { return createDeviceWatchdogRequest(new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create DWR message.", e); } return null; } public DisconnectPeerAnswer createDisconnectPeerAnswer(DisconnectPeerRequest request, DiameterAvp[] avps) throws AvpNotAllowedException { DisconnectPeerAnswer msg = (DisconnectPeerAnswer) this.createDiameterMessage(request.getHeader(), avps, Message.DISCONNECT_PEER_ANSWER, getApplicationId(request)); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public DisconnectPeerAnswer createDisconnectPeerAnswer(DisconnectPeerRequest request) { try { return createDisconnectPeerAnswer(request, new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create DPA message.", e); } return null; } public DisconnectPeerRequest createDisconnectPeerRequest(DiameterAvp[] avps) throws AvpNotAllowedException { DisconnectPeerRequest msg = (DisconnectPeerRequest) this.createDiameterMessage(null, avps, Message.DISCONNECT_PEER_REQUEST, baseAuthAppId); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public DisconnectPeerRequest createDisconnectPeerRequest() { try { return createDisconnectPeerRequest(new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create DPR message.", e); } return null; } public ExtensionDiameterMessage createMessage(DiameterCommand command, DiameterAvp[] avps) throws AvpNotAllowedException { ApplicationId aid = command.getCode() == AccountingRequest.commandCode ? ApplicationId.createByAccAppId(0, command.getApplicationId()) : ApplicationId.createByAuthAppId(0, command.getApplicationId()); ExtensionDiameterMessageImpl msg = (ExtensionDiameterMessageImpl) this.createDiameterMessage(null, avps, command.getCode(), aid); msg.getGenericData().setRequest(command.isRequest()); ((MessageImpl)msg.getGenericData()).setProxiable(command.isProxiable()); return msg; } public ReAuthAnswer createReAuthAnswer(ReAuthRequest request, DiameterAvp[] avps) throws AvpNotAllowedException { ReAuthAnswer msg = (ReAuthAnswer) this.createDiameterMessage(request.getHeader(), avps, Message.RE_AUTH_ANSWER, getApplicationId(request)); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public ReAuthAnswer createReAuthAnswer(ReAuthRequest request) { try { return createReAuthAnswer(request, new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create RAA message.", e); } return null; } public ReAuthRequest createReAuthRequest(DiameterAvp[] avps) throws AvpNotAllowedException { ReAuthRequest msg = (ReAuthRequest) this.createDiameterMessage(null, avps, Message.RE_AUTH_REQUEST, baseAuthAppId); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public ReAuthRequest createReAuthRequest() { try { return createReAuthRequest(new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create RAR message.", e); } return null; } public SessionTerminationAnswer createSessionTerminationAnswer(SessionTerminationRequest request, DiameterAvp[] avps) throws AvpNotAllowedException { SessionTerminationAnswer msg = (SessionTerminationAnswer) this.createDiameterMessage(request.getHeader(), avps, Message.SESSION_TERMINATION_REQUEST, getApplicationId(request)); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public SessionTerminationAnswer createSessionTerminationAnswer(SessionTerminationRequest request) { try { return createSessionTerminationAnswer(request, new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create STA message.", e); } return null; } public SessionTerminationRequest createSessionTerminationRequest(DiameterAvp[] avps) throws AvpNotAllowedException { SessionTerminationRequest msg = (SessionTerminationRequest) this.createDiameterMessage(null, avps, Message.SESSION_TERMINATION_REQUEST, baseAuthAppId); if (!msg.hasSessionId() && session != null) { msg.setSessionId(session.getSessionId()); } return msg; } public SessionTerminationRequest createSessionTerminationRequest() { try { return createSessionTerminationRequest(new DiameterAvp[0]); } catch (AvpNotAllowedException e) { logger.error("Unexpected failure while trying to create STR message.", e); return null; } } protected DiameterMessage createDiameterMessage(DiameterHeader diameterHeader, DiameterAvp[] avps, int _commandCode, ApplicationId appId) throws IllegalArgumentException { boolean creatingRequest = diameterHeader == null; Message msg = null; if (!creatingRequest) { Message raw = createMessage(diameterHeader, avps, 0, appId); raw.setProxiable(true); raw.setRequest(false); msg = raw; } else { Message raw = createMessage(diameterHeader, avps, _commandCode, appId); raw.setProxiable(true); raw.setRequest(true); msg = raw; } int commandCode = creatingRequest ? _commandCode : diameterHeader.getCommandCode(); DiameterMessage diamMessage = null; switch (commandCode) { case Message.ABORT_SESSION_REQUEST: diamMessage = creatingRequest ? new AbortSessionRequestImpl(msg) : new AbortSessionAnswerImpl(msg); break; case Message.ACCOUNTING_REQUEST: diamMessage = creatingRequest ? new AccountingRequestImpl(msg) : new AccountingAnswerImpl(msg); break; case Message.CAPABILITIES_EXCHANGE_REQUEST: diamMessage = creatingRequest ? new CapabilitiesExchangeRequestImpl(msg) : new CapabilitiesExchangeAnswerImpl(msg); break; case Message.DEVICE_WATCHDOG_REQUEST: diamMessage = creatingRequest ? new DeviceWatchdogRequestImpl(msg) : new DeviceWatchdogAnswerImpl(msg); break; case Message.DISCONNECT_PEER_REQUEST: diamMessage = creatingRequest ? new DisconnectPeerRequestImpl(msg) : new DisconnectPeerAnswerImpl(msg); break; case Message.RE_AUTH_REQUEST: diamMessage = creatingRequest ? new ReAuthRequestImpl(msg) : new ReAuthAnswerImpl(msg); break; case Message.SESSION_TERMINATION_REQUEST: diamMessage = creatingRequest ? new SessionTerminationRequestImpl(msg) : new SessionTerminationAnswerImpl(msg); break; default: diamMessage = new ExtensionDiameterMessageImpl(msg); } // Finally, add Origin-Host and Origin-Realm, if not present. addOriginHostAndRealm(diamMessage); return diamMessage; } protected Message createMessage(DiameterHeader header, DiameterAvp[] avps,int _commandCode, ApplicationId appId) throws AvpNotAllowedException { try { Message msg = createRawMessage(header, _commandCode, appId); if(avps != null && avps.length > 0) { AvpSet set = msg.getAvps(); for (DiameterAvp avp : avps) { addAvp(avp, set); } } return msg; } catch (Exception e) { logger.error("Failure trying to create Diameter message.", e); } return null; } protected Message createRawMessage(DiameterHeader header, int _commandCode, ApplicationId appId) { int commandCode = 0; long endToEndId = 0; long hopByHopId = 0; ApplicationId aid = null; if (header != null) { commandCode = header.getCommandCode(); endToEndId = header.getEndToEndId(); hopByHopId = header.getHopByHopId(); aid = (commandCode == AccountingRequest.commandCode) ? ApplicationId.createByAccAppId(header.getApplicationId()) : ApplicationId.createByAuthAppId(header.getApplicationId()); } else { //FIXME: This is the only one ;[ commandCode = _commandCode; endToEndId = (long) (Math.random()*1000000); hopByHopId = (long) (Math.random()*1000000)+1; aid = appId == null? ApplicationId.createByAuthAppId(0,0) : appId; } try { Message msg = stack.getSessionFactory().getNewRawSession().createMessage(commandCode, aid, hopByHopId, endToEndId); return msg; } catch (Exception e) { logger.error( "Failure while treying to create raw message.", e ); } return null; } protected void addAvp(DiameterAvp avp, AvpSet set) { if (avp instanceof GroupedAvp) { AvpSet avpSet = set.addGroupedAvp(avp.getCode(), avp.getVendorId(), avp.getMandatoryRule() != DiameterAvp.FLAG_RULE_MUSTNOT, avp.getProtectedRule() == DiameterAvp.FLAG_RULE_MUST); DiameterAvp[] groupedAVPs = ((GroupedAvp) avp).getExtensionAvps(); for (DiameterAvp avpFromGroup : groupedAVPs) { addAvp(avpFromGroup, avpSet); } } else if (avp != null) { set.addAvp(avp.getCode(), avp.byteArrayValue(), avp.getVendorId(), avp.getMandatoryRule() != DiameterAvp.FLAG_RULE_MUSTNOT, avp.getProtectedRule() == DiameterAvp.FLAG_RULE_MUST); } } /** * */ public void clean() { this.session = null; } /* (non-Javadoc) * @see net.java.slee.resource.diameter.base.DiameterMessageFactory#createMessage(net.java.slee.resource.diameter.base.events.DiameterHeader, net.java.slee.resource.diameter.base.events.avp.DiameterAvp[]) */ public DiameterMessage createMessage(DiameterHeader header, DiameterAvp[] avps) throws AvpNotAllowedException { return this.createDiameterMessage(header, avps, header.getCommandCode(), getApplicationId(header)); } private void addOriginHostAndRealm(DiameterMessage msg) { if(!msg.hasOriginHost()) { msg.setOriginHost(new DiameterIdentity(stack.getMetaData().getLocalPeer().getUri().getFQDN().toString())); } if(!msg.hasOriginRealm()) { msg.setOriginRealm(new DiameterIdentity(stack.getMetaData().getLocalPeer().getRealmName())); } } private ApplicationId getApplicationId(DiameterMessage msg) { ApplicationId applicationId = null; DiameterAvp[] avps = msg.getAvps(); // Try to get Application-Id from Message AVPs if (avps != null) { for (DiameterAvp avp : avps) { if (avp.getCode() == DiameterAvpCodes.ACCT_APPLICATION_ID) { applicationId = ApplicationId.createByAccAppId(avp.getVendorId(), avp.longValue()); break; } else if (avp.getCode() == DiameterAvpCodes.AUTH_APPLICATION_ID) { applicationId = ApplicationId.createByAuthAppId(avp.getVendorId(), avp.longValue()); break; } } } if (applicationId == null) { applicationId = msg.getCommand().getCode() == AccountingRequest.commandCode ? ApplicationId.createByAccAppId(ApplicationId.Standard.DIAMETER_COMMON_MESSAGE) : ApplicationId.createByAuthAppId(ApplicationId.Standard.DIAMETER_COMMON_MESSAGE); } return applicationId; } private ApplicationId getApplicationId(DiameterHeader header) { return header.getCommandCode() == AccountingRequest.commandCode ? ApplicationId.createByAccAppId(header.getApplicationId()) : ApplicationId.createByAuthAppId(header.getApplicationId()); } }