/*
* 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;
}
}