clinuxpipeforkmkfifo

Segmentation fault (core dumped) with FIFO pipes and fork communication between server and client


I'm writing a project where you start the server in one terminal, and in other terminals that are clients you can send messages from one user to another using FIFO pipes. Server creates FIFO pipe that reads messages from clients. Client creates FIFO pipe to read messages from server.

In one terminal to start the server I type ./projectname --start and in client i type ./projectname --login nickname. When I close the client terminal my server receives segmentation fault(core dumped) error message. I tried to get rid of this in every possible way I know for x hours. How can it be fixed?

I have also tried to register users using the void verifyloginclient(char *login) function but parent proccess is unable to receive information from child and is stuck in infinite while(1) sending some message to server that also crashes server with segmentation fault so it's commented for now.

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

char userlist[10][30];
int succesfulllogin = 1;


void handler(int signum){
    pid_t pid;
    pid = wait(NULL);
    succesfulllogin = 0;
    printf("Parent knows child %d finished\n", (int)pid);
    printf("Parent ending...\n");
}
void sig_handler_parent(int signum){
    printf("signal response from child!\n");
    succesfulllogin = 0;
    exit(0);
}
void sig_handler_child(int signum){
    printf("signal from parent\n");
    succesfulllogin = 0;
    exit(0);
}

void verifyloginclient(char *login)
{
    int fd;
    char buf[256];
    char buf2[256];
    snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
    if((fd = open(buf, O_WRONLY)) == -1){
        perror("openFdloginclient");
        exit(EXIT_FAILURE);
    }
    snprintf(buf2, sizeof buf2, "%s%s%s", login, " /login ",login);
    if((write(fd, buf2, strlen(buf2))) == -1){
        perror("writeloginclient");
    }
    close(fd);
}

int verifyloginserwer(char *login)
{
    // check if login is on the userlist
        int flagcmp = -1;
        int x;
        int indeks=0;
        for(int i=0;i<10;i++){
            x = strcmp(&userlist[i][0],login);
            if(x==0){
                flagcmp = i;
            }
        }
        if(flagcmp == -1){ //if it doesnt exist we add him to first free slot
            for(int i=0;i<10;i++){
                if(userlist[i][0]=='\0'){
                    strcpy(userlist[i],login);
                    printf("userlist: %s\n", userlist[i]);
                    succesfulllogin = 1;
                    break;
                }
                else{
                    indeks++;
                }
            }
        }
        else if(flagcmp != -1 || indeks==10){
            fprintf(stderr, "loggin error!\n");
            succesfulllogin = 0;
            return 2;
        }
        return 0;
}


int splitstring(char *source, int desiredlength, char **s1,char **s2)
{
    int len;

    len = strlen(source);
    if (desiredlength > len)
        return(0);
    *s1 = (char *) malloc(sizeof(char) * desiredlength);
    *s2 = (char *) malloc(sizeof(char) * len-desiredlength+1);
    if(s1 ==NULL || s2 == NULL)
        return 0;
    strncpy(*s1,source,desiredlength);
    strncpy(*s2,source+desiredlength, len-desiredlength);

    return(1);
}

void startserwer()
{
    int fdserwer;
    int fdanuluj;
    int fd;
    char readbuf[80];
    int read_bytes;
    char buf[256]; //pipe server
    char buf2[256]; //pipe client
    char buf3[256]; // message to client
    for(int i=0;i<10;i++){ // declare userlist
        userlist[i][0] = '\0';
    }
    
    snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");

    umask(0);
    if(mkfifo(buf, 0777) == -1){
        perror("mkfifoserwer");
        exit(EXIT_FAILURE);
    }

    while(1){

        if((fdserwer = open(buf, O_CREAT | O_RDONLY))== -1){
            perror("openFdserwer");
            exit(EXIT_FAILURE);
        }

        if((read_bytes = read(fdserwer, &readbuf, sizeof(readbuf)))== -1){
            perror("readbytes");
        }
        else{
            readbuf[read_bytes] = '\0';

            //SENDER LOGIN
            char senderlogin[80];
            strcpy(senderlogin, readbuf);
            char *token = strtok(senderlogin, " ");
            printf("%s\n", token);
            strcpy(senderlogin, token);

            int b;
            char *loginnadawcy;
            char *resztakomendy;
            b = splitstring(readbuf, (int) strlen(token)+1,&loginnadawcy,&resztakomendy);
            if(b!=1){
                printf("error in command\n");
            }
            else{
                loginnadawcy[strlen(token)]='\0';

                //COMMAND NAME AFTER SLASH /
                char command[80];
                strcpy(command, readbuf);
                token = strtok(NULL, " ");
                printf("%s\n",token);
                strcpy(command, token);

                int a;
                char *komenda;
                char *reszta;
                a = splitstring(resztakomendy, (int)strlen(token)+1,&komenda,&reszta);
                if(a!=1){
                printf("error\n");
                }
                else{

                    komenda[strlen(token)]='\0';

                    if(strcmp(komenda,"/login")==0){
                        if(verifyloginserwer(senderlogin)==2){
                            //open client pipe
                            snprintf(buf2, sizeof buf2, "%s%s%s", "fifopipes/",senderlogin,".fifo");
                            
                            if((fdanuluj = open(buf2, O_WRONLY)) == -1){
                                perror("openFdanuluj");
                                exit(EXIT_FAILURE);
                            }
                            //SEND MESSAGE TO CLIENT
                            snprintf(buf3, sizeof buf3, "%s%s", "serwer ", "end");

                            if((write(fdanuluj, buf3, strlen(buf3))) == -1){
                                perror("writeFdanuluj");
                            }
                            close(fdanuluj);
                        }
                    }
                    else if(strcmp(komenda,"/w")==0){
                        //RECEIVER LOGIN
                        char receiverlogin[80];
                        token = strtok(NULL, " ");
                        printf("%s\n",token);
                        strcpy(receiverlogin, token);

                            
                        int r;
                        char *login;
                        char *message;
                        r = splitstring(reszta,(int)strlen(token)+1,&login,&message);
                        if(r!=1){
                            printf("error\n");
                        }
                        else{
                            //RECEIVE INFORMATION
                            login[strlen(receiverlogin)]='\0';
                            printf("from %s to %s: %s and length is %d \n", senderlogin, login, message, (int)strlen(message));
                                    
                            //OPEN CLIENT PIPE
                            snprintf(buf2, sizeof buf2, "%s%s%s", "fifopipes/",receiverlogin,".fifo");
                            if((fd = open(buf2, O_WRONLY))== -1){
                                perror("openFd");
                                exit(EXIT_FAILURE);
                            }
                            //SEND MESSAGE TO CLIENT
                            snprintf(buf3, sizeof buf3, "%s%s%s", senderlogin," ",message);
                            if( (write(fd, buf3, strlen(buf3) )) == -1){
                                perror("writeopenfd");
                            }
                            close(fd);
                        }
                    }
                }
            }
        }
        close(fdserwer);
    }
    unlink(buf);
}


void clientchild(char *login)
{
    int fd;
    char readbuf[80];
    int read_bytes;
    char buf[256];
    snprintf(buf, sizeof buf, "%s%s%s", "fifopipes/",login,".fifo");

    umask(0);
    if(mkfifo(buf, 0777) == -1){
        perror("mkfifoclient");
        exit(EXIT_FAILURE);
    }

    while(1){

        if((fd = open(buf, O_CREAT | O_RDONLY)) == -1){
            perror("openFdchild");
            exit(EXIT_FAILURE);
        }
        
        if((read_bytes = read(fd, &readbuf, sizeof(readbuf))) == -1){
            perror("readfdchild");
        }
        else{
            readbuf[read_bytes] = '\0';

            //SENDER LOGIN
            char nickname[80];
            strcpy(nickname, readbuf);
            char * token = strtok(nickname, " ");
            //printf("%s\n",token);
            int r;
            char *login;
            char *message;
            r = splitstring(readbuf,(int)strlen(token)+1,&login,&message);
            if(r!=1){
                printf("blad\n");
            }
            else{
                login[strlen(token)]='\0';
                if(strcmp(login,"serwer")==0 && strcmp(message,"end")==0){
                    printf("Login error. Closing...\n");
                    close(fd);
                    break;
                }
                printf("%s: %s and length is %d \n", login, message, (int)strlen(message));
                close(fd);
                //printf("Received string: \"%s\" and length is %d \n", readbuf, (int)strlen(readbuf));
            }
            //free(login);
            //free(message);
        }
    }
    unlink(buf);
}

void clientparent(char *login)
{
    signal(SIGQUIT,sig_handler_parent);
    int fd;
    int stringlen;
    char readbuf[80];
    char buf[256];
    char buf2[256];
    snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
    printf("FIFO_CLIENT: Send messages infinitely\n");

    while(1){

        if((fd = open(buf, O_WRONLY)) == -1){
            perror("openFdparent");
            exit(EXIT_FAILURE);
        }
        //printf("Enter string: ");
        fgets(readbuf, sizeof(readbuf), stdin);
        stringlen = strlen(readbuf);
        readbuf[stringlen - 1] = '\0';
        snprintf(buf2, sizeof buf2, "%s%s%s", login," ",readbuf);

        if(strlen(login)+1 == strlen(buf2)){
            printf("Error\n");
            break;
        }
        else{

            if((write(fd, buf2, strlen(buf2))) == -1){
                perror("writeparent");
            }
            printf("Sent string: \"%s\" and string length is %d \n", buf2, (int)strlen(buf2));
        }
    }
    close(fd);
}

void splitclient(char *login)
{
    printf("login: %s\n", login);
    pid_t pid = fork();
    printf("fork returned: %d\n", (int) pid);

    //signal(SIGCHLD, handler);

    if (pid < 0){
        perror("Fork failed");
    }
    else if (pid == 0){
        signal(SIGQUIT,sig_handler_child);
        printf("I am the child with pid %d\n", (int) getpid());
        char buf[256];
        snprintf(buf, sizeof buf, "%s%d", "Child ",(int) getpid());
        //kod dziecka
        clientchild(login);
        //kill(getppid(),SIGQUIT);
        exit(0);
    }
    else{
        // We must be the parent
        printf("I am the parent, waiting for child to end \n");

        //kod rodzica
        clientparent(login);
        pid_t childpid = wait(NULL);
        printf("Parent knows child %d finished\n", (int)childpid);
        printf("Parent ending...\n");
    }

}

int main(int argc, char **argv)
{

    while(1)
    {
        int c;
        int option_index = 0;
        static struct option long_options[] =
        {
            {"start", no_argument, NULL, 's'},
            {"login", required_argument, NULL, 'l'},
            {0, 0, 0, 0}
        };

        

        c = getopt_long (argc, argv, "sl:", long_options, &option_index);

        if (c == -1)
            break;

        switch (c)
        {
            case 's':
                printf("start server\n");
                startserwer();
                break;

            case 'l':
                printf("login with option %s \n", optarg);
                    //verifyloginclient(optarg);
                    splitclient(optarg);
                break;

            case '?':
                break;

            default:
                abort();
        }
    }

    if (optind < argc)
    {
        printf("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        putchar ('\n');
    }


    return 0;
}

Solution

  • From this piece in the code in startServer():

    if((read_bytes = read(fdserwer, &readbuf, sizeof(readbuf)))== -1){
        perror("readbytes");
    }
    else{
        :
        char *token = strtok(senderlogin, " ");
        :
        strcpy(senderlogin, token);
        b = splitstring(readbuf, (int) 
        strlen(token)+1,&loginnadawcy,&resztakomendy);
    

    You are not validating if token is a non-NULL pointer post tokenization. In the case the child exits, read() would return a 0 (and not -1 as a failure), indicating EOF as the man tells:

    RETURN VALUE
    On success, the number of bytes read is returned (zero indicates end of file),

    Thus the senderlogin buffer would be empty and wouldn't yield any tokens. You need to factor in this case and have appropriate null checks in place. Adding a null chek will lead to a graceful exit of the server program.