How to send structs with pointers through sockets in C - c

I have this struct in my server and client
typedef struct email{
unsigned char * message;
}mail;
And I want to send it through TCP sockets in C. But I have problems when the struct contains a pointer. I want to send all together, not parameter by parameter
I have this code for server and client:
Client:
mail messageServer;
printf("Choose message: ");
scanf("%s",messageServer.message);
printf("Message: %s\n", messageServer.message);
send(fd, &messageServer, sizeof(struct email), 0);
Server:
mail messageServer;
printf("Before recv\n");
recv(fd2, &messageServer, sizeof(struct email), 0);
printf("After recv");
printf("Message: %s\n",messageServer.message);
But when I execute it, I have a segmentation fault on server

You can't send pointers over any form of data protocol, doing so doesn't make any sense. Only send data.
In this case only the contents pointed at by message are useful information. The surrounding struct and the pointer message are only of concern to your local application.
It's common practice to write serialization/deserialization routines that convert between structs and raw data. You usually need those anyway, to deal with other things such as network endianess and struct alignment.

In general you cannot send the structure with all referenced data in one send call.
The pointer can point anywhere, so without specific preconditions, the memory where the pointer might point to is not necessarily next to the memory where the structure is stored.
The pointer value from the client is not a valid pointer when transferred to the server, so even if you would transfer all data you would have to adjust the pointer on the server.
Read about Serialization
There is an error in the client code:
mail messageServer;
printf("Choose message: ");
scanf("%s",messageServer.message);
The pointer field messageServer.message is uninitialized. You have to assign the address of a buffer where scanf can write the data.
Additionally you should limit the string length in the scanf format string to avoid writing past the end of the array.

Related

How can I possibly send this struct over network?

I've got the following struct:
struct fetch_info_t {
u_int8_t grocery_type;
u_int8_t arg[1024];
} __attribute__((packed));
I'd like to send this over a socket to a server, to request data. I'd very much like to avoid any libraries, such as protobuf.
grocery_type can be any value between 1 and 255. Some grocery types, say type 128, must provide additional information. I'ts not enough to provide type 128, I'd also like to provide Cheeses as a string. Having that said, type 129 must provide a number, u_int32_t and not a string, unlike 128.
Basically I've allocated 1024 bytes for the additional information the system may require. The question is, how do I send it over a socket, or more specifically, populate arg with the right information non-system-dependant? I know htonl on the number could be used, but how do I actually set the buffer value to that?
I'd imagine that the info sending would actually eventually be casting the struct pointer to unsigned char array and send it like that over a socket. Let me please know if there's a better way.
You cannot assign directly the 32-bit value to the array
because the correct alignment is not guaranteed.
memcpy() will just replicate the bytes with not alignment problem.
u_int32_t the_value=htonl( ... );
struct fetch_info_t the_info;
the_info.grocery_type=129;
memcpy(the_info.arg, &the_value, sizeof(the_value));
Then, because your structure is packed, you can send it with
send(my_socket, &the_info,
sizeof(the_info.grocery_type)+sizeof(the_value), 0);
In case you need to send a string
char *the_text= ... ;
size_t the_size=strlen(the_text)+1;
struct fetch_info_t the_info;
the_info.grocery_type=128;
memcpy(the_info.arg, the_text, the_size);
send(my_socket, &the_info,
sizeof(the_info.grocery_type)+the_size, 0);
Note that the '\0' is transmitted here.

Why does recvfrom care about who the data comes from

So, I'm creating a server in C which uses UDP, and I want to listen for incoming packets from many sources. Therefore, when I call ssize_t recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict), the 5th parameter, that which contains the sender's information, may vary.
Is there a way to receive the packets without knowing each individual client's address information? And, is this possible with C's library?
Here's my code:
int file_descriptor;
char data[1024];
int bytes_recved;
sockaddr_in iDontKnow;
socklen_t addr_len = sizeof(iDontKnow);
if ((bytes_recved = recvfrom(file_descriptor, data, strlen(data), 0, (struct sockaddr*)&iDontKnow, &addr_len)) < 0) {
perror("Failed to receive data");
}
I noticed that when receiving data with Java's DatagramSocket and DatagramPacket classes, the DatagramSocket's receive function took in a parameter of type DatagramPacket. This DatagramPacket, however, only held the object in which to place the data. So, why does C's implementation of UDP receiving require that you know the sender's information?
Is there a way to receive the packets without knowing each individual client's address information?
Well, you don't need to know the sender information beforehand, anyway. Once a packet is received, the sender information (if available) will be stored into address.
From the man page,
ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
int flags, struct sockaddr *restrict address,
socklen_t *restrict address_len);
[...] If the address argument is not a null pointer and the protocol provides the source address of messages, the source address of the received message shall be stored in the sockaddr structure pointed to by the address argument, and the length of this address shall be stored in the object pointed to by the address_len argument.
Regarding the why part, in case of connectionless sockets, unless you know of the sender address for a packet in a communication, you cannot reply or respond to the sender. So, it is required to know the sender info specifically in connectionless mode and there comes recvfrom() which, along with the received data, gives us the info about the sender, also.
EDIT:
In your code
recvfrom(file_descriptor, data, strlen(data), 0, (struct sockaddr*)&iDontKnow, &addr_len)
is wrong, as strlen(data) is UB, as you're trying to count the length of an uninitialized char array, which is not qualified to be a string. It invokes undefined behavior. You may want to use sizeof(data), as data is an array.
In case you're not interested in sender's info, just pass a NULL as the corresponding argument.
To add to that, for connectionless sockets (UDP), it's actually required to get the sender information. For connection oriented sockets, you have another stripped-down alternative , recv() which only takes care of receiving and storing the data.
This DatagramPacket, however, only held the object in which to place the data.
And the source address and port, and the length of the data.
So, why does C's implementation of UDP receiving require that you know the sender's information?
It doesn't. It has the option to tell you the source address and port. It's a result parameter, not an input.
You compare different functions from Java and C.
In C there is also a recv() function that does not provide any address.
The sole puprpose of recvfrom over recv is to get the sender's address.
Normally servers reply to packets that they receive. Wihout an address that is not possible.
If you do not care about the sender of your packets, just take recv.
Or to put it the other way around:
If you don't care about the sender, why did you pick the recvfrom version of recv?
I wonder what does the server server if it doesn't care about the client's addresses... But that is not related to your question.
You could do it like these,
int sockfd_recv;
struct sockaddr_in recvaddr;
bzero(&recvaddr, sizeof(recvaddr));
recvaddr.sin_family = AF_INET;
recvaddr.sin_port = htons(port_recv);
recvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(sockfd_recv, (struct sockaddr *)&recvaddr, sizeof(recvaddr));

Copying structure to char* buffer

Basicly i have a custom structure that contains different kind of data. For example:
typedef struct example_structure{
uint8_t* example_1[4];
int example_2[4];
int example_3;
} example_structure;
What i need to do is to copy context of this structure to a const char* buffer so i can send that copied data (buffer) using winsock2's send(SOCKET s, const char* buffer, int len, int flags) function. I tried using memcpy() but wouldn't i just copy address of pointers and not the data?
Yes, if you copied or sent that structure through a socket you would end up copying/sending pointers, which would obviously be meaningless to the recipient, however, if the recipient is running on different hardware (e.g. not the same endian), all of the data may be meaningless anyway. On top of that, differences in the amount of padding between structure members may also become a problem.
For non-trivial situations it is best to use an existing protocol (such as protobuf), or roll your own protocol, keeping in mind the potential differences in hardware representation of your data.
You need to design a protocol before you can encode the data in accord with that protocol. Decide exactly how the data will be encoded at the byte level. Then write code to encode and decode to that format that you decided on.
Do not skip the step of actually documenting the wire protocol at the byte level. It will save you pain later, I promise.
See this answer for a bit more detail.
const char* buffer
This buffer has a constant value so u cant copy anything to it. You probably don't need to copy anything. Just use send function in such a way:
send(s, (char*)&example_structure, sizeof(structure), flags)
But here is the problem with pointers in your structure (uint8_t* example_1[4];).
Sending pointers between different applications / machine does not make sense.
Hmm, your struct contains uint8_t * fields, what looks like C strings... It does not make sense copying or sending a pointer which is just a mere memory address in sending process user space.
If your struct has been (note, no pointers):
typedef struct example_structure{
uint8_t example_1[4];
int example_2[4];
int example_3;
} example_structure;
and provided you transfer it on exactly same architecture (same hardware, same compiler, same compiler options), you could do simply:
example_structure ex_struc;
// initialize the struct
...
send(s, &ex_struc, sizeof(ex_struc), flags);
And even in that case, I would strongly advise you to define and use a protocol - as already said by #DavidSchwartz, it could save you time and headaches later...
But as you have pointers, you cannot do that and must define a protocol.
it could be (but you are free to prefere little endian order, or 2 or 8 bytes for each int depending on your actual data):
one byte (or two) for length of first uint8_t array, followed by the array
above repeated 3 more times
four bytes in big endian order for first int of example_2
repeated 3 times
four bytes in big endian order for int of example_3
This clearly defines the format of a message.

read/write struct to a socket

I am trying to write from client a struct to the server with socket.
the struct is :
typedef struct R
{
int a;
int b;
double c;
double d;
double result[4];
}R;
The struct is the same at the 2 programs(server,client) and i malloc for the struct in both.
the client program:
struct R* r;
malloc..
...(fill the struct with data)
write(socket_fd,(void*)r,size of(R));
the Server program:
struct R* r;
malloc..
read(client_fd,(R*)r,size of(R));
This is not passing the struct from client to server..
How to write the struct to the server by socket??
Some basic elements of network programming are:
One read or write call might not write the total bytes you intend to
read/write. Check the return value of call. It would return number
of bytes read/written. If less bytes have been written, you should
call write in a loop until all data has been written. Same applies
to read.
Endianess of machine also matters. If you wrote an int which was
little endian (e.g. x86), when travelling on the network it would be converted into a
big endian value. You need to use apis such as htons, ntohs in POSIX to
accommodate that.
These are just starting points, but the most likely reasons of data not reaching destination in the form as you expected.
I'm assuming you are getting some data, but not in the form you are expecting. If so, it might also help to add a breakpoint in gdb and inspect the memory of r, in the client code.
You could fill the struct in sender code with 0xdeadbeef or similar debug strings(http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Magic_debug_values), to identify your data in the client memory more easily. I have found that very helpful for debugging. Like some of the other answers mentioned, endianess and partial data might be the problem. Checking the return values and error codes will help too.

Why do I cause a segmentation fault when passing pointers between local processes?

I am passing an array of pointers from server to client. However on client side I get Segmentation fault when I derefrence the received array. Server & client both are local to the OS. I am think I am making some kind of mistake in pointers & violating some pointer rule.
Here is the code:
Server.c
struct WinGoku goku,windows,gates;
struct WinGoku *array[3];
array[0] = &goku;
array[1] = &windows;
array[2] = &gates;
send(conSocket, array, sizeof(&array), 0);
Client.c
struct WinGoku **array;
int rec = recv(mySocket, array, 4, 0);
printf("bytes Recieved %d\n", rec);
int i;
for(i = 0; i<3;i++)
{
printf("%s\n",array[i]->test);
}
struct WinGoku contains only char[50] in which I am copying data with strcpy.
Send & receive are not returning -1, so data is sent and received properly.
What is the mistake that I am doing?
Server & client both are local to the OS. I am sure I am making some kind of mistake in pointers & voilating some pointer rule.
The pointers are in something called "virtual memory" space. The scope is limited to a single process.
Each of the server, client, despite being on the same computer has their own virtual memory space. These pointers are invalid in each. You must serialize (and usually marshal) the contents of memory to be sent over the network.
You can't send pointers over the network. Well, you can, technically, but they won't be pointing to the same thing on the receiving system.
If the actual objects are simple, i.e. contain no pointers, then you can send them directly instead.
sizeof(&array) isnt the size of struct WinGoku * 3
it should be (3*sizeof(WinGoku))
Edit:
pointers of a process cannot be accessed in another proccess.
you should send the whole between server and client.

Resources