Send a structure using UART [closed] - c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have a two boards:
- Master board (M board)
- Slave board (S board)
M board shall send a request to S board and the latter shall answer.
The answer of the slave is a struct:
typedef struct{
uint8_t userID;
uint8_t userPass;
uint16_t userData;
}UserTypeDef;
UserTypeDef User;
Example:
M board asks for user's information (struct) by sending the command GET_USER_INFO. S board shall return a data structure to M board.
M Board(Tx) --> GET_USER_INFO --> (Rx)S Board
S Board(Tx) --> User --> (Rx)M Board
The question is how to send such a struct using UART ?

Write a protocol document that explicitly defines how the contents of the structure should be transmitted over the network media. Then write code to implement the protocol.
The code that transmits the structure/object is "serializing" the data. The code that receives the structure/object is "deserializing". You can Google for lots of advice and examples about a variety of serialization protocols and techniques.
If you're using a binary protocol then you could serialize a C struct, by defining a uint8_t pointer to point to the the first byte in the structure and then transmit the bytes until you've transmitted the entire sizeof(struct). But this method has some pitfalls, especially if your transmitting and receiving devices use different microcontrollers and/or C compilers. If one microcontroller uses a different endianness than the other, or if one C compiler uses different struct padding rules than the other, then the deserialized data could be corrupted.
This is why you have to write a protocol document that explicitly defines the order and meaning of each byte. And you shouldn't rely on your C compiler to organize the struct exactly like your protocol. The C compiler may insert padding or may use the wrong endianness. So instead of simply incrementing a pointer through the struct, you should write serialization and deserialization routines that parse out each byte from the network protocol message and copy it to/from the appropriate byte in the struct.

The easiest way would be to just send it in binary. As long as the receiving side knows what the endianness of the sender is (and adjusts for it), you can just send the whole struct in one go. The downside here is a human looking at the serial port will just see gibberish, and it won't work if your serial port is 7 bits instead of 8.
Second easiest would be to convert the struct to hex, but still send it as one chunk of data (so for instance if your struct is {25, 54, 16745}, you could send 19364169, and have the receiver split it into fields. The downside of this method is it uses twice as many bytes as the first method.
Most difficult, but most robust would be to send the name of the field followed by the value. This is good because a human looking at the serial would easily be able to tell what's going on, and if you add a field to the struct later, the receiving software could throw an error when it sees a name it doesn't recognize. So from the example data above, you might have:
userID: 0x19, userPass: 0x36, userData: 0x4169. The downside here is it wastes a lot of bytes sending names, so if you're constrained by the speed of your serial link, you might not want to do this.

The best way to maintain readability is to encode it in a readable form.
This can be as simple as encoding the values as a string with sprintf.
char buffer[BUFFER_LEN];
sprintf(buffer, "%i:%i:%i", user.userId, user.userPass, user.userData);
send_over_uart(buffer);

Related

How to transmit struct as an array?

I've got a struct with 3 16-bit values in an embedded system:
struct {
uint16_t x;
uint16_t y;
uint16_t z;
};
The struct will be transmitted to another system running the same software on the same hardware. Transmission is done by sending a series of 8 8-bit values (send_data(uint8_t *data)).
My idea is just give send_data the address of the struct. The two final bytes would be considered garbage. Would this work? Is it safe?
This should be safe as long as you handle it correctly on the other end (don't write the two bytes to a random location for example).
I would also suggest you comment the issue clearly in the code so future maintainers don't run into trouble.
OR
You could change the structure for sending and receiving to include an name (eg padding) for the data at the end. This will allow you to null out those bytes before sending. Then the code should be quite clear to anyone working on it and if implemented right should have no effect on performance.
Would this work? - Yes (send_data the address of the struct.)
Is it safe? Operationally yes, but testing no.
Recommend to not send garbage. Pad the data given to send_data() as needed (2 bytes) and initialize the extra to something, say 0. This will ease debugging and make for consistent regression testing.

Correct way to parse network packet in C

(Excuse me if I am not able to put the question correctly. English in not my primary language.)
I am trying to parse SyncE ESMC packet. It is Ethernet slow protocol packet.
Approach 1:
For parsing this packet, I used byte by byte approach similar to what has been done here.
Approach 2:
Other way to parse the packet would be to define a 'structure' to represent the whole packet and access individual fields to retrieve the value at particular offset.
However in this approach structure padding and alignment may come into picture(which I am not sure) but on Linux various packet headers are defined in form of structure, e.g. iphdr in ip.h. IP packets (buffer) can be type casted to 'iphdr' to retrieve ip header fields, so it must be working.
Which approach is better to parse a network packet in C?
Does structure padding and aligment make any difference while parsing a packet via approach 2? If yes, how did Linux headers overcome this problem?
Approach 1 is the best for portability. It allows you to safely avoid misaligned accesses, for example. In particular, if your machine is little-endian, this approach lets you take care of the byte-swapping very easily.
Approach 2 is sometimes convenient and often is faster code to write. If structure padding gets in your way, your compiler probably provides a flag or attribute (like __attribute__((__packed__)) or #pragma pack) to work around it. If you have a little-endian machine, however, you're still going to have to byteswap fields all over the place.

passing a struct over TCP (SOCK_STREAM) socket in C

I have a small client server application in which i wish to send an entire structure over a TCP socket in C not C++. Assume the struct to be the following:
struct something{
int a;
char b[64];
float c;
}
I have found many posts saying that i need to use pragma pack or to serialize the data before sending and recieveing.
My question is, is it enough to use JUST pragma pack or just serialzation ? Or do i need to use both?
Also since serialzation is processor intensive process this makes your performance fall drastically, so what is the best way to serialize a struct WITHOUT using an external library(i would love a sample code/algo)?
You need the following to portably send struct's over the network:
Pack the structure. For gcc and compatible compilers, do this with __attribute__((packed)).
Do not use any members other than unsigned integers of fixed size, other packed structures satisfying these requirements, or arrays of any of the former. Signed integers are OK too, unless your machine doesn't use a two's complement representation.
Decide whether your protocol will use little- or big-endian encoding of integers. Make conversions when reading and writing those integers.
Also, do not take pointers of members of a packed structure, except to those with size 1 or other nested packed structures. See this answer.
A simple example of encoding and decoding follows. It assumes that the byte order conversion functions hton8(), ntoh8(), hton32(), and ntoh32() are available (the former two are a no-op, but there for consistency).
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
// get byte order conversion functions
#include "byteorder.h"
struct packet {
uint8_t x;
uint32_t y;
} __attribute__((packed));
static void decode_packet (uint8_t *recv_data, size_t recv_len)
{
// check size
if (recv_len < sizeof(struct packet)) {
fprintf(stderr, "received too little!");
return;
}
// make pointer
struct packet *recv_packet = (struct packet *)recv_data;
// fix byte order
uint8_t x = ntoh8(recv_packet->x);
uint32_t y = ntoh32(recv_packet->y);
printf("Decoded: x=%"PRIu8" y=%"PRIu32"\n", x, y);
}
int main (int argc, char *argv[])
{
// build packet
struct packet p;
p.x = hton8(17);
p.y = hton32(2924);
// send packet over link....
// on the other end, get some data (recv_data, recv_len) to decode:
uint8_t *recv_data = (uint8_t *)&p;
size_t recv_len = sizeof(p);
// now decode
decode_packet(recv_data, recv_len);
return 0;
}
As far as byte order conversion functions are concerned, your system's htons()/ntohs() and htonl()/ntohl() can be used, for 16- and 32-bit integers, respectively, to convert to/from big-endian. However, I'm not aware of any standard function for 64-bit integers, or to convert to/from little endian. You can use my byte order conversion functions; if you do so, you have to tell it your machine's byte order by defining BADVPN_LITTLE_ENDIAN or BADVPN_BIG_ENDIAN.
As far as signed integers are concerned, the conversion functions can be implemented safely in the same way as the ones I wrote and linked (swapping bytes directly); just change unsigned to signed.
UPDATE: if you want an efficient binary protocol, but don't like fiddling with the bytes, you can try something like Protocol Buffers (C implementation). This allows you to describe the format of your messages in separate files, and generates source code that you use to encode and decode messages of the format you specify. I also implemented something similar myself, but greatly simplified; see my BProto generator and some examples (look in .bproto files, and addr.h for usage example).
Before you send any data over a TCP connection, work out a protocol specification. It doesn't have to be a multiple-page document filled with technical jargon. But it does have to specify who transmits what when and it must specify all messages at the byte level. It should specify how the ends of messages are established, whether there are any timeouts and who imposes them, and so on.
Without a specification, it's easy to ask questions that are simply impossible to answer. If something goes wrong, which end is at fault? With a specification, the end that didn't follow the specification is at fault. (And if both ends follow the specification and it still doesn't work, the specification is at fault.)
Once you have a specification, it's much easier to answer questions about how one end or the other should be designed.
I also strongly recommend not designing a network protocol around the specifics of your hardware. At least, not without a proven performance issue.
It depends on whether you can be sure that your systems on either end of the connection are homogeneous or not. If you are sure, for all time (which most of us cannot be), then you can take some shortcuts - but you must be aware that they are shortcuts.
struct something some;
...
if ((nbytes = write(sockfd, &some, sizeof(some)) != sizeof(some))
...short write or erroneous write...
and the analogous read().
However, if there's any chance that the systems might be different, then you need to establish how the data will be transferred formally. You might well linearize (serialize) the data - possibly fancily with something like ASN.1 or probably more simply with a format that can be reread easily. For that, text is often beneficial - it is easier to debug when you can see what's going wrong. Failing that, you need to define the byte order in which an int is transferred and make sure that the transfer follows that order, and the string probably gets a byte count followed by the appropriate amount of data (consider whether to transfer a terminal null or not), and then some representation of the float. This is more fiddly. It is not all that hard to write serialization and deserialization functions to handle the formatting. The tricky part is designing (deciding on) the protocol.
You could use an union with the structure you want to send and an array:
union SendSomething {
char arr[sizeof(struct something)];
struct something smth;
};
This way you can send and receive just arr. Of course, you have to take care about endianess issues and sizeof(struct something) might vary across machines (but you can easily overcome this with a #pragma pack).
Why would you do this when there are good and fast serialization libraries out there like Message Pack which do all the hard work for you, and as a bonus they provide you with cross-language compatibility of your socket protocol?
Use Message Pack or some other serialization library to do this.
Usually, serialization brings several benefits over e.g. sending the bits of the structure over the wire (with e.g. fwrite).
It happens individually for each non-aggregate atomic data (e.g. int).
It defines precisely the serial data format sent over the wire
So it deals with heterogenous architecture: sending and recieving machines could have different word length and endianness.
It may be less brittle when the type change a little bit. So if one machine has an old version of your code running, it might be able to talk with a machine with a more recent version, e.g. one having a char b[80]; instead of char b[64];
It may deal with more complex data structures -variable-sized vectors, or even hash-tables- with a logical way (for the hash-table, transmit the association, ..)
Very often, the serialization routines are generated. Even 20 years ago, RPCXDR already existed for that purpose, and XDR serialization primitives are still in many libc.
Pragma pack is used for the binary compatibility of you struct on another end.
Because the server or the client to which you send the struct may be written on another language or builded with other c compiler or with other c compiler options.
Serialization, as I understand, is making stream of bytes from you struct. When you write you struct in the socket you make serialiazation.
Google Protocol Buffer offers a nifty solution to this problem. Refer here Google Protobol Buffer - C Implementaion
Create a .proto file based on the structure of your payload and save it as payload.proto
syntax="proto3"
message Payload {
int32 age = 1;
string name = 2;
} .
Compile the .proto file using
protoc --c_out=. payload.proto
This will create the header file payload.pb-c.h and its corresponding payload.pb-c.c in your directory.
Create your server.c file and include the protobuf-c header files
#include<stdio.h>
#include"payload.pb.c.h"
int main()
{
Payload pload = PLOAD__INIT;
pload.name = "Adam";
pload.age = 1300000;
int len = payload__get_packed_size(&pload);
uint8_t buffer[len];
payload__pack(&pload, buffer);
// Now send this buffer to the client via socket.
}
On your receiving side client.c
....
int main()
{
uint8_t buffer[MAX_SIZE]; // load this buffer with the socket data.
size_t buffer_len; // Length of the buffer obtain via read()
Payload *pload = payload_unpack(NULL, buffer_len, buffer);
printf("Age : %d Name : %s", pload->age, pload->name);
}
Make sure you compile your programs with -lprotobuf-c flag
gcc server.c payload.pb-c.c -lprotobuf-c -o server.out
gcc client.c payload.pb-c.c -lprotobuf-c -o client.out

DNS client in C

I am currently working on a school project which asks me to implement a DNS client, without using any library functions.
I have got to the point where i send a DNS request and Receive the Reply. I'm getting stuck at the parsing of the reply. I receive the reply in a char* array and i want to convert it into some meaningful structure, from which i can parse the answer.
I went through the RFC and i read about the packet structure, but implementing it in C is giving me problems.
Can anyone give me any examples, in C, or maybe in any other language that explains how this is done. Or any reference to a book is also fine.
Additional Details:
So, the following are the structures that i'm using.
struct result{
int type;
struct res_ip_cname ip_cname;
struct res_error error;
struct res_mx_ns mx_ns;
};
struct res_ip_cname{
char* lst;
int sec;
char* auth_flag;
};
struct res_error{
char * info;
};
struct res_mx_ns{
char * name;
unsigned short pref;
int sec;
char* auth_flag;
};
I have a char* buffer[], where im storing the response the i receive from the server. And, i need to extract information from this buffer and populate the structure result.
Thanks,
Chander
Your structures don't look like anything I recognise from the RFCs (yes, I've written lots of DNS packet decoding software).
Look at RFC 1035 in particular - most of the structures you need can be mapped directly from the field layouts show therein.
For example, you need a header (see s4.1.1):
struct dns_header {
uint16_t query_id;
uint16_t flags;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
};
Don't forget to use ntohs() to convert the wire format of these fields into your machine's native byte order. The network order is big-endian, and most machines these days are little-endian.
You'll need a "question" structure (see s4.1.2), and a generic "resource record" structure too (see s4.1.3).
Note however that the wire format of both of these starts with a variable length "label", which can also include compression pointers (see s4.1.4). This means that you can't in these cases trivially map the whole wire block onto a C structure.
Hope this helps...
If I were you I'd be using wireshark (in combination with the RFC) to inspect the packet structure. Wireshark captures and displays the network packets flowing through your computer. It lets you see both the raw data you will be receiving, and the decoded packet structure.
For example, in the screenshot below you can see the IP address of chat.meta.stackoverflow.com returned in a DNS Response packet, rendered in three different ways. Firstly, you can see a human readable version, in the middle pane of the screen. Secondly, the highlighted text in the lower left pane shows the raw DNS packet as a series of hexadecimal bytes. Thirdly, in the highlighted text in the lower left pane, you can see the packet rendered as ASCII text (in this case, mostly but not entirely, gobbledigook).
The request format and response format are quite similar - both contain variable length fields, which I guess is what you're stuck on - but if you've managed to form a request properly, you shouldn't have too much trouble parsing the response. If you can post some more details, like where exactly you're stuck, we could help better.
My advice is don't make a meal of it. Extract QDCOUNT and ANCOUNT from the header, then skip over the header, skip QDCOUNT questions, and start parsing answers. Skipping a label is easy (just look for the first byte that's 0 or has the high bit set), but decoding one is a little bit more work (you need to follow and validate "pointers" and make sure you don't get stuck in a loop). If you're only looking up addresses (and not PTR records) then you really never need to decode labels at all.

Sample read/write handling of packets in C

I'm a bit new to C, but I've done my homework (some tutorials, books, etc.) and I need to program a simple server to handle requests from clients and interact with a db. I've gone through Beej's Guide to Network programming, but I'm a bit unsure how to piece together and handle different parts of the data getting sent back and forth.
For instance, say the client is sending some information that the server will put in multiple fields. How do I piece together that data to be sent and then break it back up on the server side?
Thanks,
Eric
If I understand correctly, you're asking, "how does the server understand the information the client sends it"?
If that's what you're asking, the answer is simple: it's mutually agreed upon ahead of time that the data structures each uses will be compatible. I.e. you decide upon what your communication protocol will be ahead of time.
So, for example, if I have a client-server application where the client connects and can ask for things such as "time", "date" and can say "settime " and "setdate ", I need to write my server in such a way that it will understand those commands.
Obviously, in the above case it's trivial, since it'd just be a text-based protocol. But let's say you're writing an application that will return a struct of information, i.e.
struct Person {
char* name;
int age;
int heightInInches;
// ... other fields ...
};
You might write the entire struct out from the server/client. In this case there are a few things to be aware of:
You need to hton/ntoh properly
You need to make sure that your client and server both can understand the struct in question.
You may or may not have to align on a 4B boundary (because if you don't, different C compilers may do different things, which may burn you between the client and the server, or it may not).
In general, though, when writing a client/server app, the most important thing to get right is the communication protocol.
I'm not sure if this quite answers your question, though. Is this what you were after, or were you asking more about how, exactly, do you use the send/recv functions?
First, you define how the packet will look - what information will be in it. Make sure the definition is in an architecture-neutral format. That means that you specify it in a sequence that does not depend on whether the machine is big-endian or little-endian, for example, nor on whether you are compiling with 32-bit long or 64-bit long values. If the content is of variable length, make sure the definition contains the information needed to tell how long each part is - in particular, each variable length part should be preceded by a suitable count of its length.
When you need to package the data for transmission, you will take the raw (machine-specific) values and write them into a buffer (think 'character array') at the appropriate positions, in the appropriate format.
This buffer will be sent across the wire to the receiver, which will read it into another buffer, and then reverse the process to obtain the information from the buffer into local variables.
There are functions such as ntohs() to convert from a network ('n') to host ('h') format for a 'short' (meaning 16-bit) integer, and htonl() to convert from a host 'long' (32-bit integer) to network format - etc.
One good book for networking is Stevens' "UNIX Network Programming, Vol 1, 3rd Edn". You can find out more about it at its web site, including example code.
As already mentioned above what you need is a previously agreed means of communication. One thing that helps me is to use xmls to communicate.
e.g. You need time to send time to client then include it in a tag called time.
Then parse it on the client side and read the tag value.
The biggest advantage is that once you have a parser in place on client side then even if you have to send some new information them just have to agree on a tag name that will be parsed on the client side.
It helps me , I hope it helps you too.

Resources