/* * 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.client; 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.EventListener; import org.jdiameter.api.IllegalDiameterStateException; 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.OverloadException; import org.jdiameter.api.Request; import org.jdiameter.api.RouteException; 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; public class ExampleClient implements EventListener<Request, Answer> { private static final Logger log = Logger.getLogger(ExampleClient.class); static{ //configure logging. configLog4j(); } private static void configLog4j() { InputStream inStreamLog4j = ExampleClient.class.getClassLoader().getResourceAsStream("log4j.properties"); Properties propertiesLog4j = new Properties(); try { propertiesLog4j.load(inStreamLog4j); PropertyConfigurator.configure(propertiesLog4j); } catch (Exception e) { e.printStackTrace(); }finally { if(inStreamLog4j!=null) { try { inStreamLog4j.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } log.debug("log4j configured"); } //configuration files private static final String configFile = "org/example/client/client-jdiameter-config.xml"; private static final String dictionaryFile = "org/example/client/dictionary.xml"; //our destination private static final String serverHost = "127.0.0.1"; private static final String serverPort = "3868"; private static final String serverURI = "aaa://" + serverHost + ":" + serverPort; //our realm private static final String realmName = "exchange.example.org"; // definition of codes, IDs 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; //list of data we want to exchange. private static final String[] TO_SEND = new String[] { "I want to get 3 answers", "This is second message", "Bye bye" }; //Dictionary, for informational purposes. private AvpDictionary dictionary = AvpDictionary.INSTANCE; //stack and session factory private Stack stack; private SessionFactory factory; // //////////////////////////////////////// // Objects which will be used in action // // //////////////////////////////////////// private Session session; // session used as handle for communication private int toSendIndex = 0; //index in TO_SEND table private boolean finished = false; //boolean telling if we finished our interaction private void initStack() { if (log.isInfoEnabled()) { log.info("Initializing Stack..."); } InputStream is = null; try { //Parse dictionary, it is used for user friendly info. dictionary.parseDictionary(this.getClass().getClassLoader().getResourceAsStream(dictionaryFile)); log.info("AVP Dictionary successfully parsed."); this.stack = new StackImpl(); //Parse stack configuration is = this.getClass().getClassLoader().getResourceAsStream(configFile); Configuration config = new XMLConfiguration(is); factory = stack.init(config); if (log.isInfoEnabled()) { log.info("Stack Configuration successfully loaded."); } //Print info about applicatio 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(); //Register network req listener, even though we wont receive requests //this has to be done to inform stack that we support application Network network = stack.unwrap(Network.class); network.addNetworkReqListener(new NetworkReqListener() { @Override public Answer processRequest(Request request) { //this wontbe called. return null; } }, this.authAppId); //passing our example app id. } 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(); //ignore for now. 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."); } } /** * @return */ private boolean finished() { return this.finished; } /** * */ private void start() { try { //wait for connection to peer try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //do send this.session = this.factory.getNewSession("BadCustomSessionId;YesWeCanPassId;" + System.currentTimeMillis()); sendNextRequest(EXCHANGE_TYPE_INITIAL); } catch (InternalException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalDiameterStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (RouteException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (OverloadException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void sendNextRequest(int enumType) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { Request r = this.session.createRequest(commandCode, this.authAppId, realmName, serverURI); // here we have all except our custom avps AvpSet requestAvps = r.getAvps(); // code , value , vendor, mandatory,protected,isUnsigned32 // (Enumerated) Avp exchangeType = requestAvps.addAvp(exchangeTypeCode, (long) enumType, vendorID, true, false, true); // value // is // set // on // creation // code , value , vendor, mandatory,protected, isOctetString Avp exchengeData = requestAvps.addAvp(exchangeDataCode, TO_SEND[toSendIndex++], vendorID, true, false, false); // value // is // set // on // creation // send this.session.send(r, this); dumpMessage(r,true); //dump info on console } /* * (non-Javadoc) * * @see org.jdiameter.api.EventListener#receivedSuccessMessage(org.jdiameter * .api.Message, org.jdiameter.api.Message) */ @Override public void receivedSuccessMessage(Request request, Answer answer) { dumpMessage(answer,false); if (answer.getCommandCode() != commandCode) { log.error("Received bad answer: " + answer.getCommandCode()); return; } AvpSet answerAvpSet = answer.getAvps(); Avp exchangeTypeAvp = answerAvpSet.getAvp(exchangeTypeCode, vendorID); Avp exchangeDataAvp = answerAvpSet.getAvp(exchangeDataCode, vendorID); Avp resultAvp = answer.getResultCode(); try { //for bad formatted request. if (resultAvp.getUnsigned32() == 5005 || resultAvp.getUnsigned32() == 5004) { // missing || bad value of avp this.session.release(); this.session = null; log.error("Something wrong happened at server side!"); finished = true; } switch ((int) exchangeTypeAvp.getUnsigned32()) { case EXCHANGE_TYPE_INITIAL: // JIC check; String data = exchangeDataAvp.getUTF8String(); if (data.equals(TO_SEND[toSendIndex - 1])) { // ok :) send next; sendNextRequest(EXCHANGE_TYPE_INTERMEDIATE); } else { log.error("Received wrong Exchange-Data: " + data); } break; case EXCHANGE_TYPE_INTERMEDIATE: // JIC check; data = exchangeDataAvp.getUTF8String(); if (data.equals(TO_SEND[toSendIndex - 1])) { // ok :) send next; sendNextRequest(EXCHANGE_TYPE_TERMINATING); } else { log.error("Received wrong Exchange-Data: " + data); } break; case EXCHANGE_TYPE_TERMINATING: data = exchangeDataAvp.getUTF8String(); if (data.equals(TO_SEND[toSendIndex - 1])) { // good, we reached end of FSM. finished = true; // release session and its resources. this.session.release(); this.session = null; } 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(); } catch (IllegalDiameterStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (RouteException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (OverloadException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* * (non-Javadoc) * * @see org.jdiameter.api.EventListener#timeoutExpired(org.jdiameter.api. * Message) */ @Override public void timeoutExpired(Request request) { } 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 + "\" />"); } } } public static void main(String[] args) { ExampleClient ec = new ExampleClient(); ec.initStack(); ec.start(); while (!ec.finished()) { try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }