I've modified this C datagram (UDP) socket client example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#define SERVERPORT "4950"
volatile sig_atomic_t is_shutdown = 0;
void handler_signal(int signal)
{
if (signal == SIGINT)
{
is_shutdown = 1;
}
}
int main(int argc, char *argv[])
{
int socket_fd;
struct addrinfo hints, *server_info, *temp;
int result;
int number_bytes;
if (argc != 2)
{
fprintf(stderr, "usage: executable [hostname]\n");
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
result = getaddrinfo(argv[1], SERVERPORT, &hints, &server_info);
if (result != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
return 1;
}
// loop through all the results and make a socket
for(temp = server_info; temp != NULL; temp = temp->ai_next)
{
socket_fd = socket(temp->ai_family, temp->ai_socktype, temp->ai_protocol);
if (socket_fd == -1)
{
fprintf(stderr, "socket error: %s\n", strerror(errno));
continue;
}
break;
}
freeaddrinfo(server_info);
if (temp == NULL)
{
fprintf(stderr, "failed to create socket\n");
return 2;
}
//int hostname_length = strlen(argv[2]);
unsigned long counter = 0;
const size_t buffer_length = 50;
char buffer[buffer_length];
memset(&buffer, 0, buffer_length);
while (!is_shutdown)
{
snprintf(buffer, buffer_length, "%lu", counter++);
number_bytes = sendto(socket_fd, buffer, buffer_length, 0, temp->ai_addr, temp->ai_addrlen);
if (number_bytes == -1)
{
fprintf(stderr, "sendto error: %s\n", strerror(errno));
break;
}
printf("sent %d bytes to %s.\n", number_bytes, argv[1]);
}
result = close(socket_fd);
if (result == -1)
{
fprintf(stderr, "close error: %s\n", strerror(errno));
}
printf("exiting application\n");
return 0;
}
It fails on sendto
function with Invalid argument (errno 22)
on the second iteration of the loop. It works on the first.
However, the code works (client keeps sending messages in an infinite loop and server successfully receives them) if I change it to the following:
//...
//create a copy to pass it later
socklen_t length = temp->ai_addrlen;
struct sockaddr *address = temp->ai_addr;
while (!is_shutdown)
{
snprintf(buffer, buffer_length, "%lu", counter++);
number_bytes = sendto(socket_fd, buffer, buffer_length, 0, address, length);
//...
What have I done here? What am I missing? I am not sure what is going on here.
As Frankie_C pointed in his [comment]:
temp
is a pointer to struct addrinfo
which value is assigned from server_info
. But when you freeaddrinfo(server_info)
the memory is released and temp
points to nowhere. It works the first time because no memory reuse has happened yet. But after memory reuse it become invalid. Try to make a copy of data before to free the structure.