I'm trying to use the following struct to put my received data in:
typedef struct packet {
uint8_t magic;
uint8_t version;
uint16_t body_length;
char *body;
} packet;
This is the printing function:
void displayPacket (struct packet p){
printf("Magic : %u\n",p.magic);
printf("Version : %u\n",p.version);
printf("Body Length: %d\n",ntohs(p.body_length));
printf("Body : %s\n",p.body);
}
In my main, I'm trying this to save the received data in my structure:
unsigned char reply[1024];
struct packet reply_packet;
reply_packet.body = malloc(1021);
reply_packet.body[1020] = '\0';
rc = recvfrom(s,&reply_packet,sizeof(reply_packet),0,NULL,NULL);
displayPacket(reply_packet);
free(reply_packet.body);
close(s);
Output:
Magic : 95
Version : 1
Body Length: 1008
[1] 4741 segmentation fault ./network
Magic, Version, Body Length are the expected output of the begining of the packet. The packet has a 1024 bytes max limit size, because of a protocol followed by the other peers.
However, I have a segmentation fault, provoked by my displayPacket function, more precisely this line:
printf("Body : %s\n",p.body);
This is the valgrind output if it can help:
==4886== Invalid read of size 1
==4886== at 0x4C32CF2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4886== by 0x4E994D2: vfprintf (vfprintf.c:1643)
==4886== by 0x4EA0F25: printf (printf.c:33)
==4886== by 0x108EFD: displayPacket (network.c:143)
==4886== by 0x1090FF: main (network.c:189)
==4886== Address 0x3030000000000000 is not stack'd, malloc'd or (recently) free'd
==4886==
==4886==
==4886== Process terminating with default action of signal 11 (SIGSEGV)
==4886== General Protection Fault
==4886== at 0x4C32CF2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4886== by 0x4E994D2: vfprintf (vfprintf.c:1643)
==4886== by 0x4EA0F25: printf (printf.c:33)
==4886== by 0x108EFD: displayPacket (network.c:143)
==4886== by 0x1090FF: main (network.c:189)
It's been bugging me for hours even though it seems pretty trivial...
The expected output would the content of the rest of the content in the packet. So far I've been able to do it.
What are the solutions you'd think of to solve this problem please?
Thanks.
EDIT 1 :
Solved the segmentation fault issue by modifying the structure like this:
typedef struct packet {
uint8_t magic;
uint8_t version;
uint16_t body_length;
char body[1021];
} packet;
and the rest of the code:
unsigned char reply[1024];
struct packet reply_packet;
reply_packet.body[1020] = '\0';
rc = recvfrom(s,&reply_packet,sizeof(reply_packet),0,NULL,NULL);
printf("body[0] %d\n",reply_packet.body[0]);
displayPacket(reply_packet);
close(s);
displayPacket remained unchanged.
packet.body is a pointer. It doesn't really make sense to pass a pointer since an address to data on a remote machine is useless plus you will always read only sizeof(pointer) bytes for the body. You can do something like this:
typedef struct packet {
uint8_t magic;
uint8_t version;
uint16_t body_length;
char body[MAX_BODY_SIZE];
} packet;
You are crashing in the printf because you are dereferencing a bad pointer. Even if body has a variable length you can set MAX_BODY_SIZE to the largest possible size and then use the body_length field to figure out the actual size.
You can also get rid of the reply variable since it is not used.
Update: You're close. You are printing the body as a number. Since you mentioned ASCII I assume its a string. Also, you need to NULL terminate based on the actual length of body. Here's what you need:
struct packet reply_packet;
rc = recvfrom(s,&reply_packet,sizeof(reply_packet),0,NULL,NULL);
reply_packet.body[packet.body_length] = '\0'; // null term after the body length
printf("body[0] %s\n",reply_packet.body); // change to %s and remove [0], you want the pointer not a character
displayPacket(reply_packet);