0

I try to use two FIFOs, one for the child process and one for the parent. First, the child should write a question in the parent FIFO. Parent waits until question arrives, then reads it, answers it and writes the answer in the child's FIFO. Child waits for the answer, then reads it and puts it out.

Problem is, somehow the child reads always an empty answer and I don't know why.

Code below:

MAIN:

int main() {

    pid_t child, parent;
    char quest[PIPE_BUF];
    int n=0;
    switch(fork()) {

        case CHILD: {

            while(n==0){
                printf("Bitte Frage stellen\n");
                n=scanf("%s", quest);
            }
        }
            child = getpid();
            question(quest, child);
            break;
        case ERROR:
            perror("fork():");
            break;

        default:
            printf("waiting for input\n");
            parent = getpid();
            oracle(parent);
    }

    return EXIT_SUCCESS;

}

CHILD FUNCTION

void question(const char *buf, pid_t pid ){
    char filename[PIPE_BUF];

    if (mkfifo(ANSW, 0666) == -1){
        if(errno == EEXIST)
            perror(" oracle mkfifo:");
        else{
            perror(" oracle mkfifo:");
            exit(EXIT_FAILURE);
        }
    }
    int fd, fd2;
    fd = open(FIFO, O_WRONLY);
    char quest[PIPE_BUF + 1];
    char answer[PIPE_BUF + 1];
    int n = 0;

    sprintf(quest, "%d:", pid);
    strcat(quest,buf);
    write(fd,quest,strlen(quest));
    sleep(2);
    fd2= open(ANSW,O_RDONLY);

    printf("%s\n", answer);
    while(1) {
        n=read(fd2, answer, strlen(answer));
        if (n == -1) {
            perror(" client read():");
            break;
        } else if (n > 0){
            puts(answer);
            break;
        }
    }
    remove("/tmp/answer.me");
    unlink(FIFO);
    unlink(ANSW);
    close(fd);
    close(fd2);
}

PARENT FUNCTIONS:

int isVokal(const char* buf, int i){

    if (buf[i] == '?' && ((buf[i-1] == 'a') || (buf[i-1] == 'e') ||(buf[i-1] == 'i') || (buf[i-1] == 'o') || (buf[i-1] == 'u')))
        return 1;
    else
        return 0;
}

int answer(char * buf, pid_t pid){
    int i = 0;
    int fd = open(ANSW, O_WRONLY);
    char answer[PIPE_BUF + 1];
    size_t x = strlen(buf);
    buf[x+1] = '\0';
    do{
        i++;
        if(buf[i] == '\0'){
            --i;
            if(buf[i] != '?'){

                sprintf(answer, "%s","Dies ist keine Frage.\n");
                write(fd,answer, strlen(answer));
                i++;
            }else if(isVokal(buf,i)){

                sprintf(answer, "%s","Yes!\n");
                write(fd,answer, strlen(answer));
                i++;
            }else{

                sprintf(answer, "%s","No!\n");
                write(fd,answer, strlen(answer));
                i++;
            }
        }

    }while ( buf[i] != '\0');
    close(fd);

    return 0;
}

void oracle(pid_t pid) {
    int i = 1;
    if ((mkfifo(FIFO, 0666) == -1)){
        if(errno == EEXIST)
            perror(" oracle mkfifo:");
        else{
            perror(" oracle mkfifo:");
            exit(EXIT_FAILURE);
        }
    }
    int fd = open(FIFO, O_RDONLY);
    if(fd == -1)
        perror(" oracle open():");
    char buf[PIPE_BUF + 1];

    while (i) {
        printf("waiting for input\n");
        int n = read(fd, buf, PIPE_BUF);

        if (n == -1)
            perror(" oracle read():");
        else if (n >= 0)
            i=answer(buf, pid);

    }
    close(fd);
    remove("/tmp/ask.me");
    unlink(FIFO);
    unlink(ANSW);

}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Cryptos90
  • 3
  • 2
  • `quest` is not initiated before you enter the while loop in the child, so that loop never terminates. – William Pursell Jun 12 '20 at 11:48
  • But why are you using a named pipe? `man pipe` – William Pursell Jun 12 '20 at 11:50
  • 1
    The lines `remove("/tmp/answer.me");` and `remove("/tmp/ask.me");` seem unrelated to anything else in the code. They should probably be removed. The compound statement within `case CHILD:` is curious; the braces don't seem to be necessary. You don't check for errors from system calls like `open()` — that's always a very, very bad omission. You don't check that `write()` systems calls work. When things are not working as you expect, checking the system call results is crucial. – Jonathan Leffler Jun 12 '20 at 12:33
  • Pipes are not 'block' oriented, so, usually the message must be fixed in length or there needs to be some delimiter separating messages. Otherwise, how is the reader of a pipe to know when they have consumed all of a message – user3629249 Jun 13 '20 at 00:12
  • The posted code fragments do not compile! Amongst other things, they are missing the needed `#include` statements for the needed header files. Please correct these deficiencies – user3629249 Jun 13 '20 at 00:19
  • regarding: `case CHILD: {` `CHILD` is not defined. Perhaps you meant `0` – user3629249 Jun 13 '20 at 00:20
  • regarding: `char quest[PIPE_BUF];` the macro `PIPE_BUF` is not defined – user3629249 Jun 13 '20 at 00:22
  • regarding: `size_t x = strlen(buf); buf[x+1] = '\0';` For the function: `strlen()` to work, the `buf` must already contain a trailing NUL byte. So that second statement is not needed. – user3629249 Jun 13 '20 at 00:37
  • regarding: `if(fd == -1) perror(" oracle open():");` if the call to `perror()` is executed, then the program has failed. This is unrecoverable. The next operation is to 'cleanup', then call `exit( EXIT_FAILURE );` Not to continuing to execute as if everything is ok. – user3629249 Jun 13 '20 at 00:39
  • there is plenty more wrong with the code logic, but the above comments should get you thinking in the right direction. – user3629249 Jun 13 '20 at 00:43

0 Answers0