typecasting...

A

aki

i am receiving a buffer from network as char pointer.
char * buffer;
this is an argument of my function.
well i want to decode this buffer.
buffer contain a packet with different fields
as

code of size 1 byte contain inter value
identifier of size 1 byte contain integer value
and
length of size 2 byte. contain integer value.

as struct lcpHeader
{
uint8_t code;
uint8_t identifier;
uint16_t length;
};

i want to access it all fields.
1) code field

struct lcpHeader *hdr;
hdr=(struct lcpHeader*)buffer;

when i do switch(hdr->code)
will it give integer value contained in the code....?

how to access other fielsd?
i hope i have made clear what i wann do?
 
A

Alf P. Steinbach

* aki:
i am receiving a buffer from network as char pointer.
char * buffer;
this is an argument of my function.
well i want to decode this buffer.
buffer contain a packet with different fields
as

code of size 1 byte contain inter value
identifier of size 1 byte contain integer value
and
length of size 2 byte. contain integer value.

as struct lcpHeader
{
uint8_t code;
uint8_t identifier;
uint16_t length;
};

i want to access it all fields.
1) code field

struct lcpHeader *hdr;
hdr=(struct lcpHeader*)buffer;

when i do switch(hdr->code)
will it give integer value contained in the code....?

Yes. Whether that is what's meant to be interpreted as code is another
question. That depends on whether your platform-dependent definitions
correspond to the format of the data.

how to access other fielsd?

Think about how you accessed the code field.

i hope i have made clear what i wann do?

Nope.
 
G

Gianni Mariani

aki said:
i am receiving a buffer from network as char pointer.
char * buffer;
this is an argument of my function.
well i want to decode this buffer.
buffer contain a packet with different fields
as

code of size 1 byte contain inter value
identifier of size 1 byte contain integer value
and
length of size 2 byte. contain integer value.

as struct lcpHeader
{
uint8_t code;
uint8_t identifier;
uint16_t length;
};

i want to access it all fields.
1) code field

struct lcpHeader *hdr;
hdr=(struct lcpHeader*)buffer;

when i do switch(hdr->code)
will it give integer value contained in the code....?

how to access other fielsd?
i hope i have made clear what i wann do?

Anything coming over the wire needs to be absolutely consistent to avoid
security problems.

Before performing the cast, make sure there are enough bytes that have
been read into the buffer (so you don't depend on uninitialized garbage).


.... psuedo code shows one way of doing it ...

// returns negative number indicating the number of bytes short
// returns a positive number indicating the number of bytes used
// returns 0 when the packet cannot be parsed

int decode( const char * buffer, int bytes_read )
{
// check there are enough bytes
if ( sizeof( lcpHeader ) > bytes_read )
{
// return a negative number indicating the number of bytes
// needed before decoding can proceed
return bytes_read - sizeof( lcpHeader );
}

const lcpHeader *hdr = reinterpret_cast< const lcpHeader *>(buffer);

// need to make sure you correct for endianness
const uint16_t length = EndianAdjust( hdr->length );

.... you need to make sure we're using hdr->length correctly here..

if ( length > bytes_read )
{
// still don't have enough bytes
return bytes_read - length;
}

// all the bytes for the packet are now in the buffer ..

switch ( hdr->code )
{
default :
{
// unknown code

... version issue ? ...
return 0; // 0 is an error
}

case 1 :
{
return decode_data_for_code_1(
buffer + sizeof( * hdr ), length - sizeof( * hdr )
);
break;
}

}

// return number of bytes consumed
return length;
}

..... do the same thing for code 1 ...

int decode_data_for_code_1( const char * buffer, int bytes_read )
{
.....
}


It can't be stressed how critical it is to make sure you do not try to
parse uninitialized data or make any assumptions on the length of the
data available (i.e. over flow any buffers by assuming the data from the
wire is smaller that your allocated buffer). You also need to set
reasonable size limits to data so as not to cripple your protocol but
also not allow for denial of service attacks.
 
A

ajk

when i do switch(hdr->code)
will it give integer value contained in the code....?

yep

how to access other fielsd?

same way u accessed 'code'

hdr->identifier
hdr->length
 
J

James Kanze

i am receiving a buffer from network as char pointer.
char * buffer;
this is an argument of my function.
well i want to decode this buffer.
buffer contain a packet with different fields
as
code of size 1 byte contain inter value

In what format?
identifier of size 1 byte contain integer value

In what format?
and
length of size 2 byte. contain integer value.

In what format?
as struct lcpHeader
{
uint8_t code;
uint8_t identifier;
uint16_t length;
};

You'll have to extract the individual bytes and reconstruct them
into whatever struct you want to use. There's no guarantee that
the internal format of a struct is in any way related to some
arbitrary network protocol.
i want to access it all fields.
1) code field
struct lcpHeader *hdr;
hdr=(struct lcpHeader*)buffer;
when i do switch(hdr->code)
will it give integer value contained in the code....?

Exceptionally, this one probably will, as long as the possible
values in the code field are in the range [0,128). The one
guarantee you have about structure layout is that the address of
the first element is the same as the address of the struct.

If the code can be negative, or have values greater that or
equal to 128, you'll have to convert the char to either signed
or unsigned char.
how to access other fielsd?

By extracting the bytes from the buffer, recombining them to
form whatever type you want, and assigning the results to the
field in the struct. Without knowing more about the format,
it's impossible to say precisely how to do this.
 
J

Jim Langston

aki said:
i am receiving a buffer from network as char pointer.
char * buffer;
this is an argument of my function.
well i want to decode this buffer.
buffer contain a packet with different fields
as

code of size 1 byte contain inter value
identifier of size 1 byte contain integer value
and
length of size 2 byte. contain integer value.

as struct lcpHeader
{
uint8_t code;
uint8_t identifier;
uint16_t length;
};

i want to access it all fields.
1) code field

struct lcpHeader *hdr;
hdr=(struct lcpHeader*)buffer;

when i do switch(hdr->code)
will it give integer value contained in the code....?

how to access other fielsd?
i hope i have made clear what i wann do?

Do a sizeof kpHeader and make sure it's 32. It may be different although it
seems like it may be okay in this instance. I'm talking about padding
spaces. Lets say, for example, you had a structure:

struct kpHeader
{
uint8_t Code;
uint32_t Length;
};

You might think the sizeof that woudl be 40, but might be suprised that the
size (on my platform) would be 64. That's why it's generally not a good
idea to try to cast socket data into a structure as padding may throw it
off. I do not know if your system is 32 bit aligned, 16 bit, etc...For the
most part, two bytes followed by a short (16 bit) should fit in 32 bits, but
there is no guarantee.
 
A

aki

Anything coming over the wire needs to be absolutely consistent to avoid
security problems.

Before performing the cast, make sure there are enough bytes that have
been read into the buffer (so you don't depend on uninitialized garbage).

... psuedo code shows one way of doing it ...

// returns negative number indicating the number of bytes short
// returns a positive number indicating the number of bytes used
// returns 0 when the packet cannot be parsed

int decode( const char * buffer, int bytes_read )
{
// check there are enough bytes
if ( sizeof( lcpHeader ) > bytes_read )
{
// return a negative number indicating the number of bytes
// needed before decoding can proceed
return bytes_read - sizeof( lcpHeader );
}

const lcpHeader *hdr = reinterpret_cast< const lcpHeader *>(buffer);

// need to make sure you correct for endianness
const uint16_t length = EndianAdjust( hdr->length );

.... you need to make sure we're using hdr->length correctly here..

if ( length > bytes_read )
{
// still don't have enough bytes
return bytes_read - length;
}

// all the bytes for the packet are now in the buffer ..

switch ( hdr->code )
{
default :
{
// unknown code

... version issue ? ...
return 0; // 0 is an error
}

case 1 :
{
return decode_data_for_code_1(
buffer + sizeof( * hdr ), length - sizeof( * hdr )
);
break;
}

}

// return number of bytes consumed
return length;

}

.... do the same thing for code 1 ...

int decode_data_for_code_1( const char * buffer, int bytes_read )
{
....

}

It can't be stressed how critical it is to make sure you do not try to
parse uninitialized data or make any assumptions on the length of the
data available (i.e. over flow any buffers by assuming the data from the
wire is smaller that your allocated buffer). You also need to set
reasonable size limits to data so as not to cripple your protocol but
also not allow for denial of service attacks.

thanks for your all comments....

one thing i missed earlier to write is..
the buffer i am receiving not only contains lcpHeader but also data
after that.
the data field is variable as the data length varies with code field
of lcpHeader..
my question is..
can i do check for enough bytes....
// check there are enough bytes
like u HAVE DONE ABOVE...
as now payload of lcpHeader is not fixed...
 
A

aki

Do a sizeof kpHeader and make sure it's 32. It may be different although it
seems like it may be okay in this instance. I'm talking about padding
spaces. Lets say, for example, you had a structure:

struct kpHeader
{
uint8_t Code;
uint32_t Length;

};

You might think the sizeof that woudl be 40, but might be suprised that the
size (on my platform) would be 64. That's why it's generally not a good
idea to try to cast socket data into a structure as padding may throw it
off.
yes there can be additional padding bits..if required from other
side...
but then how can socket data be casted into structures...
any solution to padding... problem....
how is then packet data received correctly....


I do not know if your system is 32 bit aligned, 16 bit, etc...For the
 
J

James Kanze

Pick a language. You multi-posted the same message to comp.lang.c.

Thanks for pointing that out. That way I can adjust my
responses, and not get chewed out by the C'ers for suggesting
e.g. std::vector.:).

As it happens, he has hit on a question where the basic issues
are the same in the two languages. C++ tries to be compatible
with C where POD structures are involved. (For those in clc: in
C++, a POD ("Plain Ordinary Data") structure corresponds, more
or less, to the subset of what you could write in C.) The rules
for padding, etc., are the same. And C++'s rules are exactly
the same concerning the representation of arithmetic types.
(Strictly speaking, not quite: the C++ rules correspond to those
in C90, which is, of course, out of date. But the next version
of C++ will be compatible with C99, and in practice, I don't
think it makes a difference here. C99's decision to limit
integer representations to 1's complement, 2's complement and
signed magnitude was, I believe, just a recognition that no
other conforming representations did exist.)
 
J

James Kanze

Do a sizeof kpHeader and make sure it's 32.

I don't know of any platform today where this is the case. On
most platforms, I'd expect a size of 4, but of course, there's
absolutely no guarantee. (Note that by using the integral types
from C99, he has ensured 8 bit bytes... and that the code won't
compile on every platform.)
It may be different although it
seems like it may be okay in this instance. I'm talking about padding
spaces. Lets say, for example, you had a structure:
struct kpHeader
{
uint8_t Code;
uint32_t Length;
};
You might think the sizeof that woudl be 40, but might be suprised that the
size (on my platform) would be 64.

You must have a really exotic machine. On all of my systems
(PC's and Sparc based, 32 and 64 bits, Windows, Linux and
Solaris), it's 8.
That's why it's generally not a good
idea to try to cast socket data into a structure as padding may throw it
off. I do not know if your system is 32 bit aligned, 16 bit, etc...For the
most part, two bytes followed by a short (16 bit) should fit in 32 bits, but
there is no guarantee.

The alignment is only part of the problem. There's also the
question of representation of the values. He still has problems
with regards to byte order, however, and if he tries the above
for an Internet protocol, on a PC, it won't work.

The only real solution is to access the buffer one byte at a
time, and use the individual bytes to build up the target data
type. For an Internet protocol, a two byte integral field
starting at offset 2 could be read by:

(buffer[ 2 ] & 0xFF) << 8 | (buffer[ 1 ] & 0xFF)

(I generally try to declare such buffers as unsigned char,
rather than plain char, so as to not need the "& 0xFF" all over
the place.)

The correct way to read his structure would be:

struct lcpHeader
getHeader(
unsigned char buffer )
{
lcpHeader result = {} ;
result.code = buffer[ 0 ] ;
result.identifier = buffer[ 1 ] ;
result.length = (buffer[ 2 ] << 8) | buffer[ 3 ] ;
return result ;
}

This, of course, supposes that the types in the transmission
buffer are also unsigned (or at least limited to non-negative
values), and that the protocol uses the standard Internet
protocol representations (which is far from universal). It
works regardless of the size or representation of the internal
types, and regardless of what padding might have been inserted
by the compiler.
 
J

James Kanze


Maybe. It will work if the integer value in code is in the
range [0,128), but only because code is the first element of the
struct.
same way u accessed 'code'
hdr->identifier
hdr->length

No. Neither of these are guaranteed to work. On a PC, at least
with Internet protocols, the second doesn't work. And all
depend somewhat on the compiler.
 
G

Gianni Mariani

aki wrote:
....
one thing i missed earlier to write is..
the buffer i am receiving not only contains lcpHeader but also data
after that.
the data field is variable as the data length varies with code field
of lcpHeader..
my question is..
can i do check for enough bytes....
// check there are enough bytes
like u HAVE DONE ABOVE...
as now payload of lcpHeader is not fixed...

That depends on the protocol. If the length in the header is the entire
length of the message (logical thing to do) then you're all set. Without
knowing what the protocol is, I can't answer your question.
 
D

Drew Lawson

aki said:
yes there can be additional padding bits..if required from other
side...
but then how can socket data be casted into structures...
any solution to padding... problem....
how is then packet data received correctly....

I'm not sure what answers are portable, but one is to check your
compiler options to see if there are any that specify how/whether
data structures are packed. There are certainly some out there
that allow you to turn off padding, and certain embedded applications
(like those dealing with raw packet data) often make sure that one
of them is in use.

Another method is to keep your byte buffer as a byte buffer and
look at each "field" explicitly:

(unit16_t *)(buffer+2)

As hinted at elsewhere, you still have to adjust for bit/byte/word
ordering and whether they agree with network order. The last place
I worked on that sort of stuff had sets of BYTE_SWAP(), etc. macros
that were built up from compiler macros that (IIRC) indicated the
local ordering. On some hardware they ended up being no-ops. (This
was working in C, but in details that I believe are identical in
C++.)

If this is a learning project, you can simplify things by using the
same hardware types on both ends of the wire and just ignoring the
ordering issue. In my college days, that was easy. All the socket
connections were going to the same machine we were on.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top