Reputation: 11
I'm creating a C program with a server-client bases.
I've been trying to redirect the stdin to a named pipe I created and I've managed to put a client writing to the pipe. On the server side I opened the same pipe, closed stdin and redirected the stdin, using dup (tried with dup2 as well), to the pipe.
I have to read the input with the function getline. The problem is it reads the first input correctly, but recieves only nulls after it. I'll add a sample to the question.
server:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
main () {
char* str;
size_t size=0;
int pshell_in;
unlink("/tmp/par-shell-in");
if(mkfifo("/tmp/par-shell-in", 0777) < 0){
fprintf(stderr, "Error: Could not create pipe\n");
exit(-1);
}
if((pshell_in = open("/tmp/par-shell-in", O_CREAT | O_RDONLY, S_IRUSR)) < 0){
fprintf(stderr, "Error: Failed to open file\n");
exit(-1);
}
dup2(pshell_in, 0);
close(pshell_in);
while(1) {
if (getline(&str, &size, stdin)<0) {
printf("Oh dear, something went wrong with getline()! %s\n", strerror(errno));
return -1;
}
printf("%s", str);
}
}
* I know its null cause I've printed it with read (instead of redirecting) and it prints (null).
client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#define VECTORSIZE 7
int main() {
char* buf;
int pshell_in;
size_t size=0;
if((pshell_in = open("/tmp/par-shell-in", O_WRONLY, S_IWUSR)) < 0){
fprintf(stderr, "Error: Failed to open file\n");
exit(-1);
}
printf("%d\n", pshell_in);
while(1) {
if (getline(&buf, &size, stdin) < 0) {
return -1;
}
write(pshell_in, buf, 256);
}
}
Can anyone help me with this one?
Upvotes: 1
Views: 2266
Reputation: 755054
FIFOs are funny things. If a process tries to open one for reading, it will block until there's a process that opens it for writing. Conversely, if a process tries to open one for writingt, it will block until there's a process that opens it for reading. However, multiple processes can open it for reading or writing. When there are no more processes with it open for reading, writes will fail; when there are no more processes with it open for writing, reads will fail. And when the operations fail, you have to close and reopen the FIFO to continue processing data afresh.
I strongly suspect you're running into problems because of these behaviours.
Additionally, your client write code is dubious; you aren't paying any attention to how much data was read. You have:
while(1) {
if (getline(&buf, &size, stdin) < 0) {
return -1;
}
write(pshell_in, buf, 256);
}
If, as is probable, you read less than 256 characters of input in the line, then it's quite possible that you go writing beyond the bounds of the array that was allocated by getline()
. It's also distinctly possible that some or even most of that data is null bytes. However, the (null)
you're seeing in the server typically indicates that you're trying to print a string but passed printf()
a null pointer. Whatever's going on, most of it is undefined behaviour which is a Bad Thing™ and should be avoided at all costs.
You should have something more like:
ssize_t nbytes;
while ((nbytes = getline(&buf, &size, stdin)) > 0)
{
if (write(pshell_in, buf, nbytes) != nbytes)
{
fprintf(stderr, "Short write to FIFO\n");
break;
}
}
free(buf);
Note how this only writes as much data as was read and doesn't assume that 256 bytes were available to be written.
Upvotes: 2