I am trying to send and receive a following struct via send() and recv(). Following are the struct that I am trying to send/recv, my client.c, and server.c codes. It seems like my server is unable to deserialize the struct received. When I run the following server code, I am getting segfaults and the print statements after recv() aren't printing anything. Any advice on how to properly send and receive a struct?
typedef struct {
char* path;
int flags;
} OpenStruct;
client.c
OpenStruct *os = malloc(sizeof(OpenStruct));
char* pathname = "overflow.txt"
os -> path = pathname;
os -> flags = 1;
int ret = send(socket_fd, &os, sizeof(OpenStruct), 0);
server.c
int openSize = sizeof(OpenStruct);
OpenStruct *os = (OpenStruct*)malloc(openSize);
char* buf1 = malloc(openSize);
while ((rv = recv(sessfd, (void *)buf1, openSize, 0))>0) {
memcpy(&os, buf1, intBuf);
char* path = os -> pathname;
fprintf(stderr, "content of path %s\n", path);
}
CodePudding user response:
error #1 - you fill your struct field with the pointer to the string not the data itself
os->path = pathname;
error #2 - os is already a pointer, you take the address of the pointer.
int ret = send(socket_fd, &os, sizeof(OpenStruct), 0);
The proper way would be something like this:
typedef struct {
int pathSize;
int flags;
} OpenStruct;
client.c:
char* pathname = "overflow.txt"
OpenStruct *os = malloc(sizeof(OpenStruct));
if (os == null) {
perror("");
return false;
}
os -> pathSize = htons(strlen(pathname));
os -> flags = 1;
int ret = send(socket_fd, os, sizeof(OpenStruct), 0);
if (ret != sizeof(OpenStruct)) {
perror("")
return false;
}
ret = send(socket_fd, pathname, os->pathSize, 0);
if (ret != os->pathSize) {
perror("")
return false;
}
You get the idea
CodePudding user response:
There should be tons of tutorials about serialization and deserialization.
The main purpose of that process is to convert your internal representation into some external representation that is reversible.
Normally this involves taking measures to deal with endianess and padding etc. But as you mentioned in comments, that should be ignored here.
A serialization function could look like this:
void serialize_OpenStruct(int socket_fd, OpenStruct *os)
{
// TODO: Add check of sent_bytes.
size_t len = strlen(os->pathname);
send(socket_fd, &len, sizeof(len), 0);
send(socket_fd, os->pasthname, len, 0);
send(socket_fd, &os->flags, sizeof(os->flags), 0);
}
The corresponding deserialization would look like this:
OpenStruct *deserialize_OpenStruct(int socket_fd)
{
// TODO: Add check of sent_bytes and malloced memory.
OpenStruct *os = malloc(sizeof(OpenStruct));
size_t len;
recv(socket_fd, &len, sizeof(len), 0);
os->pathname = malloc(len 1);
recv(socket_fd, os->pasthname, len, 0);
recv(socket_fd, &os->flags, sizeof(os->flags), 0);
return os;
}
Alternatively you could only prepare some buffer instead of using sockets directly. That would allow to use the functions both for network communication and for storing the data in a file.