FINAL UPDATE: Code updated with final working version, got everything working thanks to the code found on: How to flush stdin without requiring user input?
Im programming C and having some trouble redirecting output from a parent process to a child process using file descriptors.
The idea of all of this, is for program A to be the middleman between all the data that goes from two programs. I have a process A that creates a child process B which executes a execlp to a program C. There is also a program D that communicates with process A by named pipes and the idea is to redirect this communication to program C using unnamed pipes.
Right now my programs redirect the inicial communication from C to A to D correctly and from D to A correctly but fails when the redirection from A to C is supposed to happen.
I think the problem is that fgets() does not seem to retrieve the input unless two enters are given. I've tried using scanf, fscanf, getchar() and others aswell as flushing in multiple ways, nothing worked. The only problem really is the fact that two inputs seem to be required for the communication of A to C to occur. There are a million posts about this, and i've tried a lot of them to no sucess. Can anyone help? Sorry if it sounds confusing.
Process A:(middleman)
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
int main(void)
{ //0->read 1->write
int fd_out[2];
int fd_in[2];
pipe(fd_out);
pipe(fd_in);
pid_t pid = fork(); //Create process B
char s[BUFSIZ];
char s2[BUFSIZ];
if ( pid == 0 )
{
close(STDOUT_FILENO);
dup(fd_out[1]);
close(fd_out[0]);
close(STDIN_FILENO);
dup(fd_in[0]);
close(fd_in[1]);
if(execlp("./test_pipe_game","./test_pipe_game",(char*)NULL) == -1){
printf("Error EXECL\n"); //Program C
}
}else{
int fifo;
char * myfifo = "/tmp/fifo123";
mkfifo(myfifo, 0666);
close (fd_out[1]);
close(fd_in[0]);
while(1){
read(fd_out[0], s, BUFSIZ);
printf("Game said:\n%s \nsending to client...\n", s);
fifo = open(myfifo, O_WRONLY);
write(fifo, s, BUFSIZ);
close(fifo);
fifo = open(myfifo, O_RDONLY);
read(fifo, s2, BUFSIZ);
close(fifo);
printf("Client said:\n%s \nsending to game...\n", s2);
write(fd_in[1], s2, BUFSIZ);
fflush(stdout);
printf("Sent!\n");
}
}
int status;
waitpid(pid, &status, 0);
if ( WIFEXITED(status) )
{
int exit_status = WEXITSTATUS(status);
printf("Exit status of the child was %d, my pid = %d\n",
exit_status, getpid());
}
return 0;
}
Program C:(game)
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
//https://stackoverflow.com/questions/54299405/how-to-flush-stdin-without-requiring-user-input
int flush_in(FILE *file)
{
int ch;
int flags;
int fd;
fd = fileno(file);
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
return -1;
}
do {
ch = fgetc(file);
} while (ch != EOF);
clearerr(file);
if (fcntl(fd, F_SETFL, flags)) {
return -1;
}
return 0;
}
int main(){
char s[BUFSIZ];
char aux;
int c;
int i = 0;
while(1){
printf("Say something client!\n");
fflush(stdout);
//fgets(s, BUFSIZ, stdin);
scanf("%s",s);
printf("I received %s from the client!\n", s);
flush_in(stdin);
}
}
Program D(client)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
int main()
{
int fd1;
char * myfifo = "/tmp/fifo123";
char str1[BUFSIZ];
char str2[BUFSIZ];
while (1)
{
system("clear");
fd1 = open(myfifo,O_RDONLY);
read(fd1, str1, BUFSIZ);
close(fd1);
printf("The game said:\n%s\n", str1);
printf("Say something:\n");
//fgets(str2, BUFSIZ, stdin);
scanf("%s",str2);
fd1 = open(myfifo,O_WRONLY);
write(fd1, str2, BUFSIZ);
close(fd1);
}
return 0;
}
UPDATE: Like @CraigEstey and @thebusybee said my problem was using only one pipe, when i added the second pipe it solved the issue. I now have another problem, which seems to be related to reading from stdin without getting trash, i get no trash from the first 2 or 3 communications but after that fgets only reads trash. Flushing stdin does not seem to solve much. I've updated the codes if anyone wants to help!