package org.jdiameter.client.impl.parser;
/*
* Copyright (c) 2006 jDiameter.
* https://jdiameter.dev.java.net/
*
* License: GPL v3
*
* e-mail: erick.svenson@yahoo.com
*
*/
import static org.jdiameter.api.Avp.ACCT_APPLICATION_ID;
import static org.jdiameter.api.Avp.AUTH_APPLICATION_ID;
import static org.jdiameter.api.Avp.SESSION_ID;
import static org.jdiameter.api.Avp.VENDOR_SPECIFIC_APPLICATION_ID;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import org.jdiameter.api.Avp;
import org.jdiameter.api.AvpDataException;
import org.jdiameter.api.AvpSet;
import org.jdiameter.api.MetaData;
import org.jdiameter.api.Request;
import org.jdiameter.client.api.IMessage;
import org.jdiameter.client.api.IRequest;
import org.jdiameter.client.api.parser.DecodeException;
import org.jdiameter.client.api.parser.IMessageParser;
import org.jdiameter.client.impl.helpers.UIDGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MessageParser extends ElementParser implements IMessageParser {
protected Logger logger = LoggerFactory.getLogger(MessageParser.class);
protected UIDGenerator endToEndGen = new UIDGenerator(
(int) (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) & 0xFFF) << 20
);
MetaData metaData;
public MessageParser(MetaData metaData) {
this.metaData = metaData;
}
public IMessage createMessage(ByteBuffer data) throws AvpDataException {
// Read header
try {
byte[] message = data.array();
long tmp;
DataInputStream in = new DataInputStream( new ByteArrayInputStream(message) );
tmp = in.readInt();
short version = (short) (tmp >> 24);
if (version != 1) {
throw new Exception("Illegal value of version " + version);
}
tmp = in.readInt();
short flags = (short) ( (tmp >> 24) & 0xFF );
int commandCode = (int) (tmp & 0xFFFFFF);
long applicationId = ((long)in.readInt() << 32) >>> 32;
long hopByHopId = ((long)in.readInt() << 32) >>> 32;
long endToEndId = ((long)in.readInt() << 32) >>> 32;
// Read body
byte[] body = new byte[message.length - 20];
System.arraycopy(message, 20, body, 0, body.length);
AvpSetImpl avpSet = decodeAvpSet(body);
return new MessageImpl(this, commandCode, applicationId, flags, hopByHopId, endToEndId, avpSet);
}
catch(Exception exc) {
throw new AvpDataException(exc);
}
}
public AvpSetImpl decodeAvpSet(byte[] message) throws IOException {
AvpSetImpl avps = new AvpSetImpl(this);
int tmp, counter = 0;
DataInputStream in = new DataInputStream(new ByteArrayInputStream(message));
while (counter < message.length) {
int code = in.readInt();
tmp = in.readInt();
int flags = (tmp >> 24) & 0xFF;
int length = tmp & 0xFFFFFF;
long vendor = 0;
if ( (flags & 0x80) != 0 ) {
vendor = in.readInt();
}
byte[] rawData = new byte[length - (8 + (vendor == 0 ? 0:4))];
in.read(rawData);
if (length % 4 != 0) {
for (int i; length % 4 != 0; length += i) {
i = (int) in.skip((4 - length % 4));
}
}
AvpImpl avp = new AvpImpl(this, code, (short)flags, (int)vendor, rawData);
avps.addAvp(avp);
counter += length;
}
return avps;
}
public <T> T createMessage(Class<?> iface, ByteBuffer data) throws AvpDataException {
if (iface == IMessage.class) {
return (T)createMessage(data);
}
return null;
}
public <T> T createEmptyMessage(Class<?> iface, IMessage parentMessage) {
if (iface == Request.class) {
return (T) createEmptyMessage(parentMessage, parentMessage.getCommandCode());
}
else {
return null;
}
}
public IMessage createEmptyMessage(IMessage prnMessage) {
return createEmptyMessage(prnMessage, prnMessage.getCommandCode());
}
public IMessage createEmptyMessage(IMessage prnMessage, int commandCode) {
//
MessageImpl newMessage = new MessageImpl(
this,
commandCode,
prnMessage.getHeaderApplicationId(),
(short) prnMessage.getFlags(),
prnMessage.getHopByHopIdentifier(),
endToEndGen.nextLong(),
null
);
copyBasicAvps(newMessage, prnMessage, false);
return newMessage;
}
void copyBasicAvps(IMessage newMessage, IMessage prnMessage, boolean invertPoints) {
Avp avp;
// Copy session id's information
{
avp = prnMessage.getAvps().getAvp(SESSION_ID);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, avp));
}
avp = prnMessage.getAvps().getAvp(Avp.ACC_SESSION_ID);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, avp));
}
avp = prnMessage.getAvps().getAvp(Avp.ACC_SUB_SESSION_ID);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, avp));
}
avp = prnMessage.getAvps().getAvp(Avp.ACC_MULTI_SESSION_ID);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, avp));
}
}
// Copy Applicatio id's information
{
avp = prnMessage.getAvps().getAvp(VENDOR_SPECIFIC_APPLICATION_ID);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, avp));
}
avp = prnMessage.getAvps().getAvp(ACCT_APPLICATION_ID);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, avp));
}
avp = prnMessage.getAvps().getAvp(AUTH_APPLICATION_ID);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, avp));
}
}
// Copy proxy information
{
avp = prnMessage.getAvps().getAvp(Avp.PROXY_INFO);
if (avp != null) {
AvpSet avps;
try {
avps = avp.getGrouped();
for (Avp avpp : avps) {
newMessage.getAvps().addAvp(new AvpImpl(this, avpp));
}
}
catch (AvpDataException e) {
logger.debug("Error during copy proxy avp", e);
}
}
}
// Copy route information
{
if (invertPoints) {
// set Dest host
avp = prnMessage.getAvps().getAvp(Avp.ORIGIN_HOST);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, Avp.DESTINATION_HOST, avp));
}
// set Dest realm
avp = prnMessage.getAvps().getAvp(Avp.ORIGIN_REALM);
if (avp != null) {
newMessage.getAvps().addAvp(new AvpImpl(this, Avp.DESTINATION_REALM, avp));
}
}
else {
// set Dest host
avp = prnMessage.getAvps().getAvp(Avp.DESTINATION_HOST);
if (avp != null) {
newMessage.getAvps().addAvp(avp);
}
// set Dest realm
avp = prnMessage.getAvps().getAvp(Avp.DESTINATION_REALM);
if (avp != null) {
newMessage.getAvps().addAvp(avp);
}
}
// set Orig host and rellm
try {
newMessage.getAvps().addAvp(Avp.ORIGIN_HOST, metaData.getLocalPeer().getUri().getFQDN(), true, false, true);
newMessage.getAvps().addAvp(Avp.ORIGIN_REALM, metaData.getLocalPeer().getRealmName(), true, false, true);
}
catch (Exception e) {
logger.debug("Error during copy orig destination avp", e);
}
}
}
public ByteBuffer encodeMessage(IMessage message) throws DecodeException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
byte[] rawData = encodeAvpSet((AvpSetImpl)message.getAvps());
DataOutputStream data = new DataOutputStream(out);
int tmp = (1 << 24) & 0xFF000000;
tmp += 20 + rawData.length;
data.writeInt(tmp);
tmp = (message.getFlags() << 24) & 0xFF000000;
tmp += message.getCommandCode();
data.writeInt(tmp);
data.write( toBytes(message.getHeaderApplicationId()));
data.write( toBytes(message.getHopByHopIdentifier()));
data.write( toBytes(message.getEndToEndIdentifier()));
data.write(rawData);
}
catch(Exception e) {
logger.debug("Error during encode message", e);
}
return prepareBuffer(out.toByteArray(), out.size());
}
private byte[] toBytes(long value) {
byte[] data = new byte[4];
data[0] = (byte) ((value >> 24) & 0xFF);
data[1] = (byte) ((value >> 16) & 0xFF);
data[2] = (byte) ((value >> 8) & 0xFF);
data[3] = (byte) ((value) & 0xFF);
return data;
}
public byte[] encodeAvpSet(AvpSet avps) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
DataOutputStream data = new DataOutputStream(out);
for(Avp a: avps) {
if (a instanceof AvpImpl) {
AvpImpl aImpl = (AvpImpl) a;
if (aImpl.rawData.length == 0 && aImpl.groupedData != null) {
aImpl.rawData = encodeAvpSet( a.getGrouped() );
}
data.write(encodeAvp( aImpl ));
}
}
}
catch(Exception e) {
logger.debug("Error during encode avps", e);
}
return out.toByteArray();
}
public IMessage createEmptyMessage(int commandCode, long headerAppId) {
return new MessageImpl(this, commandCode, headerAppId);
}
public <T> T createEmptyMessage(Class<?> iface, int commandCode, long headerAppId) {
if (iface == IRequest.class) {
return (T) new MessageImpl(metaData, this, commandCode, headerAppId);
}
return null;
}
public byte[] encodeAvp(AvpImpl avp) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
DataOutputStream data = new DataOutputStream(out);
data.writeInt(avp.getCode());
int flags = (byte) ( (avp.getVendorId() !=0 ? 0x80:0) |
(avp.isMandatory() ? 0x40:0) |
(avp.isEncrypted() ? 0x20:0)
);
int origLength = avp.getRaw().length + 8 + (avp.getVendorId() != 0 ? 4:0);
int newLength = origLength;
if (newLength % 4 != 0) {
newLength += 4 - (newLength % 4);
}
data.writeInt( ((flags << 24) & 0xFF000000 ) + origLength);
if (avp.getVendorId() != 0) {
data.writeInt((int)avp.getVendorId());
}
data.write(avp.getRaw());
if(avp.getRaw().length % 4 != 0) {
for(int i = 0; i < 4 - avp.getRaw().length % 4; i++) data.write(0);
}
}
catch(Exception e) {
logger.debug("Error during encode avp", e);
}
return out.toByteArray();
}
public int getNextEndToEndId() {
return endToEndGen.nextInt();
}
}