/* * JBoss, Home of Professional Open Source * Copyright XXXX, Red Hat Middleware LLC, and individual contributors as indicated * by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a full listing * of individual contributors. * 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 General Public License, v. 2.0. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License, * v. 2.0 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.example.server; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Properties; import java.util.Set; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.jdiameter.api.Answer; import org.jdiameter.api.ApplicationId; import org.jdiameter.api.Avp; import org.jdiameter.api.AvpDataException; import org.jdiameter.api.AvpSet; import org.jdiameter.api.Configuration; import org.jdiameter.api.InternalException; import org.jdiameter.api.Message; import org.jdiameter.api.MetaData; import org.jdiameter.api.Network; import org.jdiameter.api.NetworkReqListener; import org.jdiameter.api.Request; import org.jdiameter.api.Session; import org.jdiameter.api.SessionFactory; import org.jdiameter.api.Stack; import org.jdiameter.api.StackType; import org.jdiameter.server.impl.StackImpl; import org.jdiameter.server.impl.helpers.XMLConfiguration; import org.mobicents.diameter.dictionary.AvpDictionary; import org.mobicents.diameter.dictionary.AvpRepresentation; /** * @author baranowb * */ public class ExampleServer implements NetworkReqListener { private static final Logger log = Logger.getLogger(ExampleServer.class); static{ configLog4j(); } private static void configLog4j() { InputStream inStreamLog4j = ExampleServer.class.getClassLoader().getResourceAsStream("log4j.properties"); Properties propertiesLog4j = new Properties(); try { propertiesLog4j.load(inStreamLog4j); PropertyConfigurator.configure(propertiesLog4j); } catch (Exception e) { e.printStackTrace(); } log.debug("log4j configured"); } private static final String configFile = "org/example/server/server-jdiameter-config.xml"; private static final String dictionaryFile = "org/example/client/dictionary.xml"; private static final String realmName = "exchange.example.org"; // Defs for our app private static final int commandCode = 686; private static final long vendorID = 66666; private static final long applicationID = 33333; private ApplicationId authAppId = ApplicationId.createByAuthAppId(applicationID);; private static final int exchangeTypeCode = 888; private static final int exchangeDataCode = 999; // enum values for Exchange-Type AVP private static final int EXCHANGE_TYPE_INITIAL = 0; private static final int EXCHANGE_TYPE_INTERMEDIATE = 1; private static final int EXCHANGE_TYPE_TERMINATING = 2; private static final String[] TO_RECEIVE = new String[] { "I want to get 3 answers", "This is second message", "Bye bye" }; private AvpDictionary dictionary = AvpDictionary.INSTANCE; private Stack stack; private SessionFactory factory; // //////////////////////////////////////// // Objects which will be used in action // // //////////////////////////////////////// private Session session; private int toReceiveIndex = 0; private boolean finished = false; private void initStack() { if (log.isInfoEnabled()) { log.info("Initializing Stack..."); } InputStream is = null; try { dictionary.parseDictionary(this.getClass().getClassLoader().getResourceAsStream(dictionaryFile)); log.info("AVP Dictionary successfully parsed."); this.stack = new StackImpl(); is = this.getClass().getClassLoader().getResourceAsStream(configFile); Configuration config = new XMLConfiguration(is); factory = stack.init(config); if (log.isInfoEnabled()) { log.info("Stack Configuration successfully loaded."); } Set<org.jdiameter.api.ApplicationId> appIds = stack.getMetaData().getLocalPeer().getCommonApplications(); log.info("Diameter Stack :: Supporting " + appIds.size() + " applications."); for (org.jdiameter.api.ApplicationId x : appIds) { log.info("Diameter Stack :: Common :: " + x); } is.close(); Network network = stack.unwrap(Network.class); network.addNetworkReqListener(this, this.authAppId); } catch (Exception e) { e.printStackTrace(); if (this.stack != null) { this.stack.destroy(); } if (is != null) { try { is.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } return; } MetaData metaData = stack.getMetaData(); if (metaData.getStackType() != StackType.TYPE_SERVER || metaData.getMinorVersion() <= 0) { stack.destroy(); if (log.isEnabledFor(org.apache.log4j.Level.ERROR)) { log.error("Incorrect driver"); } return; } try { if (log.isInfoEnabled()) { log.info("Starting stack"); } stack.start(); if (log.isInfoEnabled()) { log.info("Stack is running."); } } catch (Exception e) { e.printStackTrace(); stack.destroy(); return; } if (log.isInfoEnabled()) { log.info("Stack initialization successfully completed."); } } private void dumpMessage(Message message, boolean sending) { if (log.isInfoEnabled()) { log.info((sending?"Sending ":"Received ") + (message.isRequest() ? "Request: " : "Answer: ") + message.getCommandCode() + "\nE2E:" + message.getEndToEndIdentifier() + "\nHBH:" + message.getHopByHopIdentifier() + "\nAppID:" + message.getApplicationId()); log.info("AVPS["+message.getAvps().size()+"]: \n"); try { printAvps(message.getAvps()); } catch (AvpDataException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private void printAvps(AvpSet avpSet) throws AvpDataException { printAvpsAux(avpSet, 0); } /** * Prints the AVPs present in an AvpSet with a specified 'tab' level * * @param avpSet * the AvpSet containing the AVPs to be printed * @param level * an int representing the number of 'tabs' to make a pretty * print * @throws AvpDataException */ private void printAvpsAux(AvpSet avpSet, int level) throws AvpDataException { String prefix = " ".substring(0, level * 2); for (Avp avp : avpSet) { AvpRepresentation avpRep = AvpDictionary.INSTANCE.getAvp(avp.getCode(), avp.getVendorId()); if (avpRep != null && avpRep.getType().equals("Grouped")) { log.info(prefix + "<avp name=\"" + avpRep.getName() + "\" code=\"" + avp.getCode() + "\" vendor=\"" + avp.getVendorId() + "\">"); printAvpsAux(avp.getGrouped(), level + 1); log.info(prefix + "</avp>"); } else if (avpRep != null) { String value = ""; if (avpRep.getType().equals("Integer32")) value = String.valueOf(avp.getInteger32()); else if (avpRep.getType().equals("Integer64") || avpRep.getType().equals("Unsigned64")) value = String.valueOf(avp.getInteger64()); else if (avpRep.getType().equals("Unsigned32")) value = String.valueOf(avp.getUnsigned32()); else if (avpRep.getType().equals("Float32")) value = String.valueOf(avp.getFloat32()); else //value = avp.getOctetString(); value = new String(avp.getOctetString(), StandardCharsets.UTF_8); log.info(prefix + "<avp name=\"" + avpRep.getName() + "\" code=\"" + avp.getCode() + "\" vendor=\"" + avp.getVendorId() + "\" value=\"" + value + "\" />"); } } } /** * @return */ private boolean finished() { return this.finished; } public static void main(String[] args) { ExampleServer es = new ExampleServer(); es.initStack(); while (!es.finished()) { try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /* * (non-Javadoc) * * @see * org.jdiameter.api.NetworkReqListener#processRequest(org.jdiameter.api * .Request) */ @Override public Answer processRequest(Request request) { dumpMessage(request,false); if (request.getCommandCode() != commandCode) { log.error("Received bad answer: " + request.getCommandCode()); return null; } AvpSet requestAvpSet = request.getAvps(); Avp exchangeTypeAvp = requestAvpSet.getAvp(exchangeTypeCode, vendorID); Avp exchangeDataAvp = requestAvpSet.getAvp(exchangeDataCode, vendorID); if (exchangeTypeAvp == null) { log.error("Request does not have Exchange-Type"); Answer answer = createAnswer(request, 5004, EXCHANGE_TYPE_TERMINATING); dumpMessage(answer,true); return answer; // set // exchange // type // to // terminating } if (exchangeDataAvp == null) { log.error("Request does not have Exchange-Data"); Answer answer = createAnswer(request, 5004, EXCHANGE_TYPE_TERMINATING); dumpMessage(answer,true); return answer; // set // exchange // type // to // terminating } // cast back to int(Enumerated is Unsigned32, and API represents it as // long so its easier // to manipulate try { switch ((int) exchangeTypeAvp.getUnsigned32()) { case EXCHANGE_TYPE_INITIAL: // JIC check; String data = exchangeDataAvp.getUTF8String(); this.session = this.factory.getNewSession(request.getSessionId()); if (data.equals(TO_RECEIVE[toReceiveIndex])) { // create session; Answer answer = createAnswer(request, 2001, EXCHANGE_TYPE_INITIAL); // set // exchange // type // to // terminating toReceiveIndex++; dumpMessage(answer,true); return answer; } else { log.error("Received wrong Exchange-Data: " + data); Answer answer = request.createAnswer(6000); } break; case EXCHANGE_TYPE_INTERMEDIATE: // JIC check; data = exchangeDataAvp.getUTF8String(); if (data.equals(TO_RECEIVE[toReceiveIndex])) { Answer answer = createAnswer(request, 2001, EXCHANGE_TYPE_INTERMEDIATE); // set // exchange // type // to // terminating toReceiveIndex++; dumpMessage(answer,true); return answer; } else { log.error("Received wrong Exchange-Data: " + data); } break; case EXCHANGE_TYPE_TERMINATING: data = exchangeDataAvp.getUTF8String(); if (data.equals(TO_RECEIVE[toReceiveIndex])) { // good, we reached end of FSM. finished = true; // release session and its resources. Answer answer = createAnswer(request, 2001, EXCHANGE_TYPE_TERMINATING); // set // exchange // type // to // terminating toReceiveIndex++; this.session.release(); finished = true; this.session = null; dumpMessage(answer,true); return answer; } else { log.error("Received wrong Exchange-Data: " + data); } break; default: log.error("Bad value of Exchange-Type avp: " + exchangeTypeAvp.getUnsigned32()); break; } } catch (AvpDataException e) { // thrown when interpretation of byte[] fails e.printStackTrace(); } catch (InternalException e) { // TODO Auto-generated catch block e.printStackTrace(); } //error, something bad happened. finished = true; return null; } private Answer createAnswer(Request r, int resultCode, int enumType) { Answer answer = r.createAnswer(resultCode); AvpSet answerAvps = answer.getAvps(); // code , value , vendor, mandatory,protected,isUnsigned32 // (Enumerated) Avp exchangeType = answerAvps.addAvp(exchangeTypeCode, (long) enumType, vendorID, true, false, true); // value // is // set // on // creation // code , value , vendor, mandatory,protected, isOctetString Avp exchengeData = answerAvps.addAvp(exchangeDataCode, TO_RECEIVE[toReceiveIndex], vendorID, true, false, false); // value // is // set // on // creation //add origin, its required by duplicate detection answerAvps.addAvp(Avp.ORIGIN_HOST, stack.getMetaData().getLocalPeer().getUri().getFQDN(), true, false, true); answerAvps.addAvp(Avp.ORIGIN_REALM, stack.getMetaData().getLocalPeer().getRealmName(), true, false, true); return answer; } }