help icon indicating copy to clipboard operation
help copied to clipboard

Server crashes with SEGFAULT after sending.

Open koshinus opened this issue 7 years ago • 1 comments

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);
    }
}

koshinus avatar May 20 '18 11:05 koshinus

If this is still a problem for you...

Have you tried running your application under valgrind? Often helpful for diagnosing memory errors.

davisjam avatar Aug 30 '18 00:08 davisjam