Server crashes with SEGFAULT after sending.
I have an async UDP-server and client. Server can make two things: place the received data in its memory or transmit placed data to another server. When i command to place some data from the client everything is fine (even several requests), but it crashes after the transmition command at the end of on_receive() function. To repeat the error you can download the project, build it with CMake, run the client and server separately and enter in client terminal something like: p-0-0-7-100-jjjjjjj and then t-0-0-188.99.88.99-9099. Full code of the current version of the project can be find here: https://github.com/koshinus/C_programs/tree/master/diploma client.c:
char buffer[1024];
char message[256];
char option[1];
const char sending_machine_addr[] = "127.0.0.1";
const uint16_t sending_machine_port = 6868;
uint32_t ipv4_addr[4];
uint32_t target_machine_addr;
uint16_t target_machine_port;
uint64_t id, block_len, offset, msg_len;
uv_loop_t * event_loop;
uv_buf_t * uv_buf = &((uv_buf_t){.base = buffer, .len = 0});
struct sockaddr_in send_addr;
void on_send(uv_udp_send_t * req, int status)
{
}
int main()
{
event_loop = uv_default_loop();
while(1)
{
printf("Wait for option symbol: ");
// We need to ignore the newline symbol after the input
scanf("%s", option);
if (!(option[0] == 'p' || option[0] == 't'))
return 0;
else
{
printf("Enter the block id: ");
scanf("%lu", &id);
printf("Enter offset in block: ");
scanf("%lu", &offset);
printf("Enter the length of a piece of data in the block: ");
scanf("%lu", &msg_len);
if (option[0] == 'p')
{
printf("Print full length of block: ");
scanf("%lu", &block_len);
printf("Print message: ");
scanf("%s", message);
fill_buffer(buffer, option[0], id, block_len, offset, msg_len, 0, 0, message);
uv_buf->len = sizeof(char) + sizeof(id) + sizeof(block_len) + sizeof(offset) +
sizeof(msg_len) + msg_len;
}
else if (option[0] == 't')
{
printf("Enter ip address of target machine: ");
scanf("%u.%u.%u.%u", &ipv4_addr[3], &ipv4_addr[2], &ipv4_addr[1], &ipv4_addr[0]);
target_machine_addr = ipv4_addr[0] | ipv4_addr[1] << 8 | ipv4_addr[2] << 16 | ipv4_addr[3] << 24;
printf("Enter port of target machine: ");
scanf("%hu", &target_machine_port);
fill_buffer(buffer, option[0], id, 0, offset, msg_len, target_machine_addr, target_machine_port, NULL);
uv_buf->len = sizeof(char) + sizeof(id) + sizeof(offset) + sizeof(msg_len) +
sizeof(target_machine_addr) + sizeof(target_machine_port);
}
uv_udp_t send_socket;
uv_udp_send_t send_req;
uv_udp_init(event_loop, &send_socket);
uv_ip4_addr(sending_machine_addr, sending_machine_port, &send_addr);
uv_udp_bind(&send_socket, (const struct sockaddr *)&send_addr, 0);
uv_udp_set_broadcast(&send_socket, 1);
uv_udp_send(&send_req, &send_socket, uv_buf, 1, (const struct sockaddr *)&send_addr, on_send);
}
}
return uv_run(event_loop, UV_RUN_DEFAULT);
}
main.c
int main(int argc, char** argv)
{
char message[40];
RiDE_logger * logger = &(RiDE_logger) { .MAX_LOG_TIME = 10*60*60, .MAX_LOG_SIZE = 100*1024*1024 };
server = &(RiDE_server){ .logger = logger };
open_log_file(logger);
#pragma omp parallel sections
{
#pragma omp section
{
while(1)
{
if (!server->started)
server_start(server);
if (time_to_close(logger))
reopen_log_file(logger);
}
}
#pragma omp section
{
while(1)
{
scanf("%s", message);
if (!strcmp(message, "server_stop"))
{
server_stop(server);
close_log_file(logger);
exit(0);
}
}
}
}
}
RiDE_server.c (only functions related with transmition):
void server_start(RiDE_server * server)
{
datas_configure(server);
server->started = 1; // started = true
struct sockaddr_in addr;
server->event_loop = uv_default_loop();
uv_udp_init(server->event_loop, &server->recv_socket);
uv_ip4_addr("0.0.0.0", 6868, &addr);
uv_udp_bind(&server->recv_socket, (const struct sockaddr *)&addr, UV_UDP_REUSEADDR);
uv_udp_recv_start(&server->recv_socket, on_allocate, on_recieve);
uv_run(server->event_loop, UV_RUN_DEFAULT);
}
void on_allocate(uv_handle_t * client, size_t suggested_size, uv_buf_t * buf)
{
buf->base = (char *)malloc(suggested_size + 1);
buf->len = suggested_size;
buf->base[suggested_size] = '\0';
}
void on_recieve(uv_udp_t * handle, ssize_t nread, const uv_buf_t * rcvbuf, const struct sockaddr * addr, unsigned flags)
{
if (nread > 0)
parse_buffer(server, rcvbuf->base);
else
log_an_error(server->logger, NO_DATA_RECEIVED);
free(rcvbuf->base);
}
void parse_buffer(RiDE_server * server, const char * buf)
{
uint64_t id, offset, data_len, block_len;
uint32_t remote_addr;
uint16_t remote_port;
// Check the first byte in received buffer
if (*buf == 'p')
{
buf++; // Skip 'p'
id = be64toh( ((uint64_t *)buf)[0] );
block_len = be64toh( ((uint64_t *)buf)[1] );
offset = be64toh( ((uint64_t *)buf)[2] );
data_len = be64toh( ((uint64_t *)buf)[3] );
char * data_ptr = (char *)(buf + sizeof(id) + sizeof(offset) + sizeof(data_len) + sizeof(block_len));
printf("p-%lu-%lu-%lu-%lu-%s\n", id, block_len, offset, data_len, data_ptr);
placing(server, id, block_len, offset, data_len, data_ptr);
}
else if (*buf == 't')
{
buf++; // Skip 't'
remote_addr = be32toh( ((uint32_t *)buf)[0] );
buf += sizeof(remote_addr); // Skip "remote machine address"-bytes in buffer
remote_port = be16toh( ((uint16_t *)buf)[0] );
buf += sizeof(remote_port); // Skip "remote machine port"-bytes in buffer
id = be64toh( ((uint64_t *)buf)[0] );
offset = be64toh( ((uint64_t *)buf)[1] );
data_len = be64toh( ((uint64_t *)buf)[2] );
printf("t-%u-%i-%lu-%lu-%lu\n", remote_addr, remote_port, id, offset, data_len);
transmition(server, remote_addr, remote_port, id, offset, data_len);
}
else
log_an_error(server->logger, UNKNOWN_COMMAND);
}
void on_sending(uv_udp_send_t * req, int status)
{
}
void transmition(RiDE_server * server, uint32_t addr, uint16_t port, uint64_t id, uint64_t offset, uint64_t length)
{
uv_udp_t send_socket;
uv_udp_send_t send_req;
struct in_addr ip_addr;
ip_addr.s_addr = addr;
struct sockaddr_in send_addr;
uv_udp_init(server->event_loop, &send_socket);
uv_ip4_addr(inet_ntoa(ip_addr), port, &send_addr);
uv_udp_bind(&send_socket, (const struct sockaddr *)&send_addr, 0);
uv_udp_set_broadcast(&send_socket, 1);
uv_buf_t * send_buf = &(uv_buf_t){.base = NULL, .len = 0};
for (uint64_t i = 0; i < server->datas_length; i++)
{
if (server->datas[i]->id == id)
{
uint64_t block_len = server->datas[i]->len;
uint64_t full_offset = sizeof(char) + sizeof(id) + sizeof(block_len) +
sizeof(offset) + sizeof(length);
send_buf->base = (char *)malloc(sizeof(char) * (full_offset + length + 1));
// If we do not do this, the remote machine will not be able to parse
fill_buffer_for_placing(send_buf->base, id, block_len, offset, length, server->datas[i]->data);
send_buf->len = length;
uv_udp_send(&send_req, &send_socket, send_buf, 1, (const struct sockaddr *)&send_addr, on_sending);
free(send_buf->base);
return;
}
else
log_an_error(server->logger, INCORRECT_ID);
}
}
If this is still a problem for you...
Have you tried running your application under valgrind? Often helpful for diagnosing memory errors.