QQ wrote on 07/05/05 :
Hello I am a newbie on network programming.
I am trying to receive a packet
if((numbytes = recvfrom(udp_fd1, buf, MAXLEN-1, 0,(struct
sockaddr*)®ister_addr, &addr_len))==-1){
fprintf(stderr, "error in recvfrom.\n");
exit(1);
}
The packet I am receiving has the following possible structure.
typedef struct struct_CN
{
unsigned char magicA;
unsigned char magicB;
unsigned short msgLen;
} CN;
typedef struct struct_Cc
{
CN msgHeader;
unsigned short action;
unsigned short devType;
unsigned short marketId;
unsigned char switchId;
} Cc;
typedef struct struct_CcA
{
CN msgHeader;
unsigned int result;
unsigned short periodType;
unsigned short authPeriod;
} CcA;
I need to read the value or magicA to decide whether structure it is Cc
or CcA.
so what should I do?
If I have followed you well, you intend to map a structure to a byte
stream. Note that the result of such an operation is highly
implementation dependent.
My guess is that the stream is structured in octets and that these
'structures' are simply a way of representing the specifications of the
data. They certainely do not represent any C-structure at all.
Why is that ? Simply because the internal data representation of a
C-structure may vary from a machine to another, due to differences in
- endianess
- type range
- data alignment
- padding
The way I understand the data mapping you have submitted is (assuming
unsigned char is one octet, unsigned chort is 2 octets and unsigned int
is 4 octets network representation, that means MSB first), correct me
if I'm wrong:
Cc data structure:
.. magicA
.. |
.. | magicB
.. | |
.. | | msgLen
.. | | |
.. | | | action
.. | | | |
.. | | | | devType
.. | | | | |
.. | | | | | marketId
.. | | | | | |
.. | | | | | | switchId
.. | | | | | | |
.. -+-+--+--+--+--+-
.. | | | | | | | |
.. -+-+--+--+--+--+-
.. | |
.. | \
.. |<header>|
..
CcA data structure:
.. magicA
.. |
.. | magicB
.. | |
.. | | msgLen
.. | | |
.. | | | result
.. | | | |
.. | | | | periodType
.. | | | | |
.. | | | | | authPeriod
.. | | | | | |
.. -+-+--+----+--+--
.. | | | | | | |
.. -+-+--+----+--+--
.. | |
.. | \
.. |<header>|
..
How to implement this ?
I suggest a data parser based on functions receiving the address ad
length of the stream to be analysed, the addres of an *internal*
C-structure receiving the extracted data, the address of the pointer to
the next-to-be-parsed-data and some returning and error status
For example (feel free to ask for details):
#include <stdio.h>
#define CN_LEN 4
#define Cc_LEN 7
#define CcA_LEN 8
typedef unsigned char uchar;
typedef unsigned long ulong;
typedef enum
{
MAGICA_Cc = 12, /* put your values here */
MAGICA_CcA = 34,
MAGICA_dummy
}
MAGICA;
typedef struct
{
MAGICA magicA;
unsigned magicB;
unsigned msgLen;
}
CN;
typedef struct
{
unsigned action;
unsigned devType;
unsigned marketId;
unsigned switchId;
}
Cc;
typedef struct
{
ulong result;
unsigned periodType;
unsigned authPeriod;
}
CcA;
typedef struct
{
CN cn;
union
{
Cc cc;
CcA cca;
}
u;
}
data_s;
/* implementation-dependent: 0 | 1 */
#define LITTE_ENDIAN 1
/* 16 bit */
unsigned ntoh (uchar const *p)
{
unsigned value = 0;
/* implementation-dependent */
#if LITTE_ENDIAN
/* little endian (Intel, for example) */
value |= (p[0] << (8 * 1));
value |= (p[1] << (8 * 0));
#else
/* big endian (Motorola, for example) */
value |= (p[0] << (8 * 0));
value |= (p[1] << (8 * 1));
#endif
return value;
}
/* 32 bit */
ulong ntohl (uchar const *p)
{
ulong value = 0;
/* implementation-dependent */
#if LITTE_ENDIAN
/* little endian (Intel, for example) */
value |= ((ulong) p[0] << (8 * 3));
value |= ((ulong) p[1] << (8 * 2));
value |= ((ulong) p[2] << (8 * 1));
value |= ((ulong) p[3] << (8 * 0));
#else
/* big endian (Motorola, for example) */
value |= ((ulong) p[0] << (8 * 0));
value |= ((ulong) p[1] << (8 * 1));
value |= ((ulong) p[2] << (8 * 2));
value |= ((ulong) p[3] << (8 * 3));
#endif
return value;
}
int CN_parser (uchar const *to_parse, CN * p_data, uchar const
**pp_next)
{
int err = 0;
uchar const *p = to_parse;
/* 1 octet */
p_data->magicA = *p;
p++;
/* 1 octet */
p_data->magicB = *p;
p++;
/* 2 octets */
p_data->msgLen = ntoh (p);
p += 2;
if (pp_next != NULL)
{
*pp_next = p;
}
return err;
}
int Cc_parser (uchar const *to_parse, Cc * p_data, uchar const
**pp_next)
{
int err = 0;
uchar const *p = to_parse;
/* 2 octets */
p_data->action = ntoh (p);
p += 2;
/* 2 octets */
p_data->devType = ntoh (p);
p += 2;
/* 2 octets */
p_data->marketId = ntoh (p);
p += 2;
/* 1 octets */
p_data->switchId = *p;
p++;
if (pp_next != NULL)
{
*pp_next = p;
}
return err;
}
int CcA_parser (uchar const *to_parse, CcA * p_data, uchar const
**pp_next)
{
int err = 0;
uchar const *p = to_parse;
/* 4 octets */
p_data->result = ntohl (p);
p += 4;
/* 2 octets */
p_data->periodType = ntoh (p);
p += 2;
/* 2 octets */
p_data->authPeriod = ntoh (p);
p += 2;
if (pp_next != NULL)
{
*pp_next = p;
}
return err;
}
int parser (uchar const *buf, size_t len, data_s * p_data)
{
/* the parameters should not be unary expressions nor functions */
#define min(a, b) ((a)<(b)?(a):(b))
int err;
/* is the length meaningful ? */
if (len >= CN_LEN + min (Cc_LEN, CcA_LEN))
{
/* parse the header */
uchar const *p_next = buf;
err = CN_parser (p_next, &p_data->cn, &p_next);
if (!err && p_next != NULL)
{
switch (p_data->cn.magicA)
{
case MAGICA_Cc:
err = Cc_parser (p_next, &p_data->u.cc, NULL);
break;
case MAGICA_CcA:
err = CcA_parser (p_next, &p_data->u.cca, NULL);
break;
default:
err = 1;
}
}
}
else
{
err = 1;
}
return err;
#undef min
}
void print (data_s * p_data)
{
#define PRT_D(data, field) \
printf ("%15s = %ld\n", #field, (ulong) data.field)
#define PRT_X(data, field) \
printf ("%15s = %lX\n", #field, (ulong) data.field)
PRT_D (p_data->cn, magicA);
PRT_D (p_data->cn, magicB);
PRT_X (p_data->cn, msgLen);
switch (p_data->cn.magicA)
{
case MAGICA_Cc:
PRT_X (p_data->u.cc, action);
PRT_X (p_data->u.cc, devType);
PRT_X (p_data->u.cc, marketId);
PRT_X (p_data->u.cc, switchId);
break;
case MAGICA_CcA:
PRT_X (p_data->u.cca, result);
PRT_X (p_data->u.cca, periodType);
PRT_X (p_data->u.cca, authPeriod);
break;
default:
;
}
printf ("\n");
}
int main (void)
{
/* simulation data */
uchar const buf_Cc[] =
{
/* header */
MAGICA_Cc,
0,
0,
7,
/* data */
/* action */
0x12,
0x34,
/* devType */
0x56,
0x78,
/* marketId */
0x9A,
0xBC,
/* switchId */
0xD,
};
uchar const buf_CcA[] =
{
/* header */
MAGICA_CcA,
0,
0,
8,
/* data */
/* result */
0x12,
0x34,
0x56,
0x78,
/* periodType */
0x9A,
0xBC,
/* authPeriod */
0xDE,
0xF0,
};
int err;
data_s data =
{0};
err = parser (buf_Cc, sizeof buf_Cc, &data);
print (&data);
err = parser (buf_CcA, sizeof buf_CcA, &data);
print (&data);
return 0;
}
--
Emmanuel
The C-FAQ:
http://www.eskimo.com/~scs/C-faq/faq.html
The C-library:
http://www.dinkumware.com/refxc.html
I once asked an expert COBOL programmer, how to
declare local variables in COBOL, the reply was:
"what is a local variable?"