I’m developing a C application to communicate with one of the real control system device. The device uses well defined protocol structure. For example, consider one of the structure that device sends as UDP packet when it is requested:-
typedef struct poll_request_s {
uint16 poll_number; /* poll number mirrored from the
* poll request */
uint16 length; /* length of the message */
/* till above it was all header section this is ACTUAL DATA */
attribute_list_t attr_list; /* this attribute list contains
* various attributes */
} poll_request_t
Now, attribute_list_t is a structure that packs various attributes and each attribute in this list is identified by an identifier number which is uint16(16 bits integer). So, in short protocol works something like this:-
- You request some data.
- You get the data in form of attribute list.
- Each attribute in attribute list has object identifier.
- You parse each attribute (convert to host byte order) using this object identifier.
- Attribute itself may contain more attribute list. (attribute-inception)
This atrtribute_list_t structure is something like below:-
typdef struct attribute_list_s {
uint16 length; /* length of attribute list */
uint16 count; /* number of attributes in this list */
uint8 attrs_data[]; /* another container to hold attributes' data */
} attribute_list_t
Now, attrs_data is only a place holder for holding all the attributes in the list. In fact this attrs_data must be casted to another structure called ava_type to read the attribute information.
typdef struct ava_type_s {
uint16 attr_id; /* type of attribute */
uint16 length; /* length of this attribute
*(this length of single attribute not whole list*/
uint8 data[]; /* another flexible array to hold data for this
* attribute type */
}
Now, in order to iterate and parse the attributes within this structure, I’m currently using this algorithm(pseudo code below):
uint8* packet = recv_packet(SOCKET);
/* this is used as packet iterator pointer */
unit8* packet_ptr = packet;
parsed_packet_t parsed_packet = malloc(SOME_SIZE);
.
. /* do header un-packing */
.
/* dont need attribute_list length so skip this 2 bytes */
parsed_packet += 2;
/* parsed packet do nee count of attributes */
parsed_packet.attribute_list->count = NTOHS(packet_ptr);
packed_ptr += 2; /* skip count */
/* now packet_ptr is pointer to attr_list */
offset = 0, i = 0;
for(i = 0 to attr_list->count) {
/* cast the attributes' data to ava_type */
packet_ptr += offset;
/* parse object identifier */
parsed_packet.attribute_list->data[i++].object_id = NTOHS(packet_ptr);
packet_ptr += 2; /* skip 2 bytes */
/* next offset would be attribute length of this packet */
attribute_length += 2 + NTOHS(packet_ptr);
packet_ptr += 2;
/* now we are pointer to actual data of i(th) attribute */
/* I've made this parser structure and hash table to
* retrieve the parser for particular attr_id */
parser* p = HASH_TABLE(ava_type->attr_id);
/* parser has function point for network order to host
* order and visa-versa */
p->ntoh(ava_type, parsed_packet.attribute_list->data[i]);
}
Now, my questions are:
- Even though, I’ve show
HASH_TABLEapproach in above algorithm but in actually, I’m using 20 to 30IF-ELSE. Since C does not havehash tableinstdlib. There are about 600 structure in protocol and I do not want to write 600if-else. What suggestions and methods do you give about parsing these structure as per theirattribute_id. - Another problem is compiler padding in the structures that I’ve defined. All my structure are defined with
flexible arrayfield for data container. Now, when I receive the message, they contain thelengthfor almost every attribute but thislengthcan not be used formalloc..ingmy parsed structure as compiler may magically add some paddings bytes and I get short of bytes. I’m usuallymalloc..ingaboutlenght + 300bytes for safety purpose. In fact, this looks to me bad memory management practice. Any suggestions on this problem?
malloc..ing the structure to parse the received messages is the biggest problem for me so far. I want some memory efficient and fast way to do it?
Also, if you’ve already done such kind of projects, would you kindly share your approach? Any suggestions or comments to put me in right direction? I want simple design without complicating things unnecessarily.
I strongly recommend you don’t use
Cstructs to define your network protocol.Cstruct layouts are dependent on:Use XDR or something that will give you a standard format. You should be able to define exactly what you have now in XDR and have all the encoding and decoding done for you automatically.