Search code examples
clinuxserversignalsposix

Reading client response crashes server


I am writing a program where a server is signaled to by another program, upon receiving the signal it reads a directory name from a shared memory segment and sends this to a client through a sock. The client sends back the contents of the directory and disconnects

My problem is that when the server receives the client response, it prints it and immediately stops listening on the port.

The program works in all other instances, such as the client connecting, not sending anything, then disconnecting.

void handler(int signal_number)
{   
    int read_size;
    char* cli_dir[1000];
    char *message , client_message[2000];
    int i = 0;

    printf("about to access shared memory");
    message = shm; //shm is the directory name in shared memory
    puts("accessed shared memory");
    printf("is gonna be sent to client %s\n",message);
    write(sock , (char*)message , strlen(message));

    while((read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {
        //read client response and log contents of the received directory
        printf("\n%s\n", (char*)client_message);
        strcpy(cli_dir[i],(char*)client_message);
        i++;
        printf("\n");
        perror("error here");
    }

    if(read_size == 0)
    {
        puts("Client disconnected");
        fflush(stdout);
        perror("error 2 here"); 
    }
    else if(read_size == -1)
    {
        perror("receiving server side failed");
    }
}

void* connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    printf("accessed connection handler");

    sock = *(int*)socket_desc;

    while(1){

        signal(SIGUSR1, handler);

        // struct sigaction sa;
        // printf("signal recieved");
        // memset(&sa, 0, sizeof(sa)); //alternative signal handler
        // sa.sa_handler = &handler;
        // sigaction(SIGUSR1, &sa, NULL);

        pause();
    }
}

Also, here is how I am accepting connections in the main function

    while( (client_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
    {
        puts("Client accepted");

        pthread_t sniff;
        new_sock = malloc(1);
        *new_sock = client_sock;

        if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
        {
            perror("could not create thread");
            return 1;
        }

        pthread_join( sniff , NULL);
        puts("client handled");
    }

    if (client_socket < 0)
    {
        perror("accept failed");
        return 1;
    }

Solution

  • First, as Martin James already said,

    printf("\n%s\n", (char*)client_message);
    

    requires a NUL-terminated string. This is not forced by your server code and if you send a NUL-terminated string from a client like

    write(fd, str, strlen(str));
    

    then you will not send a '\0' (you need to send strlen(str) + 1 bytes or add '\0' at the receiving end being careful to not overflow your buffer by 1 byte).

    Second, I'm not familiar with writing signal-safe/unsafe code, so cannot comment on this, but here may be problems too.

    Main problem

    IMHO the main problem with your code is that you declare an uninitialized array cli_dir of pointers to strings and then pass such pointer to strcpy:

    strcpy(cli_dir[i],(char*)client_message);
    

    If I get your code right, here you pass a pointer to a memory location, to which strcpy have to copy a string, but you did not allocated somehow a memory for a copy and cli_dir[i] contains now some arbitrary garbage. This most probably will result in a Segmentation fault.