package org.jacorb.orb.giop;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import org.omg.CORBA.BAD_PARAM;
import org.omg.GIOP.MsgType_1_1;
import org.omg.IOP.ServiceContext;
/**
* @author Gerald Brose, FU Berlin 1999
*
*/
public class Messages
{
/**
* <code>MSG_HEADER_SIZE</code> is the GIOP message header size constant.
*/
static final int MSG_HEADER_SIZE = 12;
/**
* The <code>service_context</code> array is to align the data following this
* array on an 8 byte boundary. This allows for adding service
* contexts to the header without having to remarshal everything
* that follows. There are already 12 bytes on the stream (the GIOP
* message header), so the next possible 8 byte boundary is
* 16. This is reached by adding an array of length 0, because that
* will only write a ulong for the length (0), which consumes 4
* bytes.
*
* This is only necessary for GIOP 1.0/1.1, because in 1.2, the
* service_context array is the last attribute of the
* [Request|Reply]Header, and the body is per spec aligned to an 8
* byte boundary.
*/
static final ServiceContext[] service_context = new ServiceContext[0];
/**
* Skips over a number of service contexts in a GIOP reply message.
*
* @param buf the array of octets containing the service context
* @param offset the index into the buffer at which the service context
* starts. This should be after the length of the service context.
* @param length the number of service contexts
* @param little_endian 0 for big-endian, 1 for little-endian
*
* @return the index of the octet following the service context
*/
private static int skipServiceContext(byte[] buf,
int offset,
int length,
boolean little_endian )
{
int pos = offset;
for( int i = 0; i < length; i++)
{
// Skip the context ID long
pos += 4;
// Skip the octet sequence
pos = skipSequence( buf, pos, 1, little_endian );
//next is context id long.
//it has to be aligned to 4 bytes
int diff = pos % 4;
if( diff != 0 )
{
pos += ( 4 - diff );
}
}
return pos;
}
/**
* Skips over a sequence in a GIOP message.
*
* @param buf the array of octets containing the sequence
* @param offset the index into the buffer at which the sequence starts.
* This should be where the length information begins.
* @param element_size the number of octets per element in the sequence
* @param little_endian 0 for big-endian, 1 for little-endian
*
* @return the index of the octet following the sequence
*/
private static final int skipSequence( byte[] buf,
int offset,
int element_size,
boolean little_endian )
{
int length = readULong( buf, offset, little_endian );
return offset + 4 + length * element_size;
}
/** directly extract request ID from a buffer */
public static int getRequestId( byte[] buf )
{
int msg_type = getMsgType( buf );
int giop_minor = getGIOPMinor( buf );
boolean little_endian = isLittleEndian( buf );
int request_id = -1;
if( giop_minor == 2 )
{
//GIOP 1.2
if( msg_type == MsgType_1_1._Request ||
msg_type == MsgType_1_1._LocateRequest ||
msg_type == MsgType_1_1._Reply ||
msg_type == MsgType_1_1._LocateReply ||
msg_type == MsgType_1_1._CancelRequest ||
msg_type == MsgType_1_1._Fragment )
{
//easy for GIOP 1.2, it's right after the message
//header
request_id = readULong( buf, MSG_HEADER_SIZE, little_endian );
}
else
{
throw new BAD_PARAM
("Messages of type " + msg_type + " don't have request ids");
}
}
else if( giop_minor == 0 || giop_minor == 1 )
{
if( msg_type == MsgType_1_1._Request ||
msg_type == MsgType_1_1._Reply )
{
// service contexts are the first entry in the header
//get the number of individual service contexts
int service_ctx_length = readULong( buf,
MSG_HEADER_SIZE,
little_endian );
if( service_ctx_length == 0 )
{
//array of length 0, so request id folows the
//array length entry
request_id = readULong( buf,
MSG_HEADER_SIZE + 4,
little_endian );
}
else
{
//get the first index after the contexts array
int pos = skipServiceContext( buf,
MSG_HEADER_SIZE + 4, // 4 bytes is ulong
service_ctx_length,
little_endian );
//the request id follows the body
request_id = readULong( buf, pos, little_endian );
}
}
else if( msg_type == MsgType_1_1._LocateRequest ||
msg_type == MsgType_1_1._LocateReply )
{
//easy, it's right after the message header
request_id = readULong( buf, MSG_HEADER_SIZE, little_endian );
}
else
{
throw new BAD_PARAM
("Messages of type " + msg_type + " don't have request ids");
}
}
return request_id;
}
public static final int getMsgSize( byte[] buf )
{
return readULong( buf, 8, isLittleEndian( buf ) );
}
public static final void setMsgSize( byte[] buf, int size )
{
if ( isLittleEndian( buf ) )
{
buf[8] = (byte) (size & 0xFF);
buf[9] = (byte)((size >> 8) & 0xFF);
buf[10] = (byte)((size >> 16) & 0xFF);
buf[11] = (byte)((size >> 24) & 0xFF);
}
else
{
buf[8] = (byte)((size >> 24) & 0xFF);
buf[9] = (byte)((size >> 16) & 0xFF);
buf[10] = (byte)((size >> 8) & 0xFF);
buf[11] = (byte) (size & 0xFF);
}
}
public static final int readULong( byte[] buf,
int pos,
boolean little_endian )
{
if( little_endian )
{
return (( (buf[pos+3] & 0xff) << 24) +
( (buf[pos+2] & 0xff) << 16) +
( (buf[pos+1] & 0xff) << 8) +
( (buf[pos] & 0xff) << 0));
}
else //big endian
{
return (( (buf[pos] & 0xff) << 24) +
( (buf[pos+1] & 0xff) << 16) +
( (buf[pos+2] & 0xff) << 8) +
( (buf[pos+3] & 0xff) << 0));
}
}
public static final boolean matchGIOPMagic(byte[] buf)
{
// The values are hard-coded to support non-ASCII platforms.
return (buf[0] == 0x47 // 'G'
&& buf[1] == 0x49 // 'I'
&& buf[2] == 0x4f // 'O'
&& buf[3] == 0x50); // 'P'
}
public static final boolean isLittleEndian( byte[] buf )
{
//this is new for GIOP 1.1/1.2
return (0x01 & buf[6]) != 0;
}
public static final boolean moreFragmentsFollow( byte[] buf )
{
//this is new for GIOP 1.1/1.2
return (0x02 & buf[6]) != 0;
}
public static final int getMsgType( byte[] buf )
{
return buf[7];
}
public static final int getGIOPMajor( byte[] buf )
{
return buf[4];
}
public static final int getGIOPMinor( byte[] buf )
{
return buf[5];
}
public static final boolean responseExpected( byte flags )
{
return flags == (byte)0x01 || flags == (byte)0x03;
}
public static final byte responseFlags( boolean response_expected )
{
return (byte) (response_expected ? 0x03 : 0x00);
}
}