Writing string to pipe - c

I am trying to send a string to a pipe in unix. When I go through a line-by-line debugging process, the call mkfifo() creates the file in the same directory as the source code. However, when I reach the open() call, the debugger is no longer able to proceed. I'm not sure why it is unable to access the pipe file.
Here's the code in question:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd;
char * myfifo = "myfifo";
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
write(fd, "Hi", sizeof("Hi"));
close(fd);
/* remove the FIFO */
unlink(myfifo);
return 0;
}
Any suggestions are appreciated. Thank you.

Normally a FIFO has to be open at both ends simultaneously before either side can proceed. Since you didn't mention anything about a reader, the most likely answer is that you haven't got one, or you haven't set it up yet. Once you do, the open will be allowed to proceed.

mkfifo(3) routes to fifo(7) which reads:
The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process. The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.
There is a solution for non-blocking read:
A process can open a FIFO in nonblocking mode. In this case, opening for read only will succeed even if no-one has opened on the write side yet, opening for write only will fail with ENXIO (no such device or address) unless the other end has already been opened.
So you could fork another process for reading:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
long strlen(char * c){
return c[0] == 0 ? 0 : 1 + strlen(++c);
}
int main()
{
int fd;
int fr;
char buf[3];
char * MESSAGE = "Hi\n";
char * myfifo = "myfifo";
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
int msglen = strlen(MESSAGE);
int child = fork();
if (child == 0){
/* read "Hi" from the FIFO (CHILD)*/
fr = open(myfifo, O_RDONLY);
read(fr, buf, msglen);
write(1, buf, msglen);
close(fr);
} else {
/* write "Hi" to the FIFO (PARENT)*/
fd = open(myfifo, O_WRONLY);
write(fd, MESSAGE, sizeof(char) * msglen);
close(fd);
/* remove the FIFO */
wait(child);
unlink(myfifo);
}
return 0;
}
I guess you have to open both ends before you write.

here is an excerpt from the man page for mkfifo() See my notes at the end
mkfifo() makes a FIFO special file with name pathname. mode
specifies the FIFO's permissions. It is modified by the process's
umask in the usual way: the permissions of the created file are (mode
& ~umask).
A FIFO special file is similar to a pipe, except that it is created
in a different way. Instead of being an anonymous communications
channel, a FIFO special file is entered into the filesystem by
calling mkfifo().
Once you have created a FIFO special file in this way, any process
can open it for reading or writing, in the same way as an ordinary
file. However, it has to be open at both ends simultaneously before
you can proceed to do any input or output operations on it. Opening
a FIFO for reading normally blocks until some other process opens the
same FIFO for writing, and vice versa. See fifo(7) for nonblocking
handling of FIFO special files.
Notes: There are two details of importance:
1) the 'mode' parameter is modified by the value of 'umask'
2) both ends of the fifo must be open at the same time
before any I/O operations can be performed.

Related

Cannot Write in Named Pipe

In this code my program crashes in when I am opening the pipe for writing.
char pipe[30];
int fd, tmp = 2;
sprintf(pipe, "root_%d", getpid());
ret_val = mkfifo(pipe, 0666);
fd = open(pipe, O_WRONLY); //HERE IS CRASHING - SUDDENLY FREEZES
write(fd, &tmp, sizeof(int));
close(fd)
All seems good, but where is my mistake;
It is an expected behavior. From man 7 fifo:
Normally, opening the FIFO blocks until the other end is opened also.
So your open does not return until somebody opens the same pipe for reading. You may want to add O_NONBLOCK flag (and likely get SIGPIPE on writing), or revisit the design.

FIFO pipe returns 0 instead of correct integer?

I am attempting to implement a basic communication between two processes. I intend for each process to receive a piece of information then transmit one back. I am new to pipes so have attempted this using this code example:
How to send a simple string between two programs using pipes?
I set up the code and it works fine, I then duplicated the code for a second pipe in order to receive another integer. However my second pipe does not transmit the integer, the program receives a 0 instead.
program1.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd; // file descriptor
int fd_b;
int data = 5;
int buf; // buffer from fifo
char * fifo_one = "/tmp/fifo_one";
char * fifo_two = "/tmp/fifo_two";
// create fifo
mkfifo(fifo_one, 0666);
// write to FIFO
fd = open(fifo_one, O_WRONLY);
write(fd, &data, sizeof(&data));
close(fd);
// remove FIFO
unlink(fifo_one);
// receive from FIFO
fd_b = open(fifo_two, O_RDONLY);
read(fd_b, &buf, MAX_BUF);
printf("Received: %d\n", buf);
close(fd_b);
return 0;
}
program2.c:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd; // file descriptor
int fd_b;
char * fifo_one = "/tmp/fifo_one";
char * fifo_two = "/tmp/fifo_two";
int buf; // buffer from fifo
int ret_dat; // return data
// receive data from fifo
fd = open(fifo_one, O_RDONLY);
read(fd, &buf, MAX_BUF);
printf("Received: %d\n", buf);
close(fd);
// decide return
if (buf == 5) {
ret_dat = 10;
}
// send data back
// create fifo
mkfifo(fifo_two, 0666);
// write to FIFO
fd_b = open(fifo_two, O_WRONLY);
write(fd_b, &ret_dat, sizeof(&ret_dat));
close(fd_b);
// remove FIFO
unlink(fifo_sendBal);
return 0;
}
The second program receives the 5, but does not send back 10 successfully,
I understand that timings effect IPC so I have tried using sleep after certain events but I cannot get it to work.
The second program receives the 5, but does not send back 10 successfully ? The property of FIFO inter process communication created by calling mkfifo() is that both process should alive to communicate each other. From the manual page of mkfifo
Once you have created a FIFO special file in this way, any process
can open it for reading or writing, in the same way as an ordinary
file. However, it has to be open at both ends simultaneously before
you can proceed to do any input or output operations on it. Opening
a FIFO for reading normally blocks until some other process opens the
same FIFO for writing, and vice versa. See fifo(7) for nonblocking
handling of FIFO special files.

Linux : Creating a simple non-blocking server and client to communicate over named pipes

I am trying to create a simple example of named pipes (FIFO). Here, the server will listen for message from the client, which writes on the named pipe, common to both of them. The special thing to be implemented is that the FIFO should be non-blocking (usage of O_NONBLOCK).
By non blocking, I mean that the writer should return immediately after writing, if there is no reader. Similarly, reader should return immediately if there is no message(no writer).
I have created the blocking version though and its working fine. I am then trying to convert it to non-blocking.
Here's the client :
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define FIFO "/tmp/myFIFO"
/*
This acts as the client, writing to the FIFO
*/
int main(int argc, char *argv[])
{
FILE *fp;
int fifo_fd;
if(argc != 2)
{
printf("Usage : ./fifo_client <message> \n");
exit(1);
}
fifo_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}
fputs(argv[1],fp);
/* Close the fp */
fclose(fp);
return 0;
}
Here's the server :
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define FIFO "/tmp/myFIFO"
/*
This acts as a server waiting for strings to be written by the client, over the FIFO
*/
int main()
{
FILE *fp;
int fifo_fd;
char buf[1024];
/* Create a FIFO */
umask(0);
if(mkfifo(FIFO,0666) < 0) /* 0666 is read and write permission*/
{
perror("Error creating FIFO");
exit(1);
}
while(1) /*endless wait, keep reading strings and print*/
{
fifo_fd = open(FIFO, O_RDONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}
if(!fgets(buf,1024,fp))
printf("Nothing to read\n");
else
printf("Message Recieved : %s\n", buf);
fclose(fp);
sleep(1);
}
return 0;
}
I run the server first.
Secondly, on second terminal, when I run the client, I get the error :
Error while open call: No such device or address
What am I missing? I did man, and the parameters seem to be correct.
EDIT
Moving the open and close calls out of the while loop, did the job. But now if the client is started without starting the server, throws the following error :
Error while open call: No such device or address
The file /tmp/myFIFO exists on file-system from previous execution of the server, must be used by the client.
The main problem is opening and closing the file in a loop. This makes no sense. There is a very short time interval between opening and closing, and your client must hit it. It has little chance to do so. The "No such device or address" message happens exactly because the client misses the instant when the file is open. This is the main problem. Try moving open, fopen and fclose out of the server loop.
You also opening for reading but fopening for writing, but I suppose it's just a typo. This combination will not run. You need to change the mode of fopen to "r".
There are other, smaller issues.
You are not checking errors in the client. In your program the client will fail to open most of thee time, but sometimes open will succeed and write will fail.
It makes little sense to use stdio for the pipe in this program. read and write would do just fine.
Last but not least, sleep is an indication of a design issue. Indeed, in this program blocking I/O would make more sense. It's OK to use sleep if you just want to experiment with non-blocking I/O, but in real programs it should be avoided.

why non-blocking write to disk doesn't return EAGAIN or EWOULDBLOCK?

I modified a program from APUE, the program first open a file, then mark the fd as non-blocking, then continue write to the fd until write return -1.
I think since disk I/O is slow, when write buffers in OS is nearly full, the write system call will return -1, and the errno should be EAGAIN or EWOULDBLOCK.
But I ran the program for about several minutes and I repeated running the program serveral times, the write system call didn't returned -1 even once! Why?
Here's the code:
#include "apue.h"
#include <errno.h>
#include <fcntl.h>
char buf[4096];
int
main(void)
{
int nwrite;
int fd = open("a.txt", O_RDWR);
if(fd<0){
printf("fd<0\n");
return 0;
}
int i;
for(i = 0; i<sizeof(buf); i++)
buf[i] = i*2;
set_fl(fd, O_NONBLOCK); /* set nonblocking */
while (1) {
nwrite = write(fd, buf, sizeof(buf));
if (nwrite < 0) {
printf("write returned:%d, errno=%d\n", nwrite, errno);
return 0;
}
}
clr_fl(STDOUT_FILENO, O_NONBLOCK); /* clear nonblocking */
exit(0);
}
The O_NONBLOCK flag is primarily meaningful for file descriptors representing streams (e.g, pipes, sockets, and character devices), where it prevents read and write operations from blocking when there is no data waiting to read, or buffers are too full to write anything more at the moment. It has no effect on file descriptors opened to regular files; disk I/O delays are essentially ignored by the system.
If you want to do asynchronous I/O to files, you may want to take a look at the POSIX AIO interface. Be warned that it's rather hairy and infrequently used, though.

Read and Write operations get bad fd and no such file

I have this C program.
I have two processes, father and son, and use semaphores to make them synchronize one at time.
The father has to write (n) numbers, ten in this case, always in the first byte of the opened file and the son has to read it.
The problem is that when I print the results, I get bad file descriptor for the write (father) and no such file for the read(the son).
Can you help me, please?? Thank you
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define FILENAME "test.txt"
#define MUTEX "/mutex"
#define READ "/read"
#define WRITE "/write"
int main(int argc, char *argv[]){
int i, pid, n=10, fd, x;
int nread, nwrite;
char c = 'a';
sem_t *mutex, *reader, *writer;
//fd = open(FILENAME, O_CREAT | O_TRUNC, 0666);
mutex = sem_open(MUTEX, O_CREAT, 0666, 1);
reader = sem_open(READ, O_CREAT, 0666, 0);
writer = sem_open(WRITE, O_CREAT, 0666, 1);
pid = fork();
fd = open(FILENAME, O_CREAT | O_TRUNC, 0777);
if(fd < 0){
perror("Open FILE error");
exit(-1);}
if(pid == 0){ // son
do{
sem_wait(reader); // si può leggere???
sem_wait(mutex);
lseek(fd, 0, SEEK_SET);
nread = read(fd, &x, sizeof(int));
if(nread <=0)
perror("Read error");
printf("Son has read (%d byte) = %d\n", nread, x);
fflush(NULL);
sem_post(mutex);
sem_post(writer);
}
while(x != (n-1));
exit(0);
}
else{
for(i=0; i<n; i++){
sem_wait(writer); // can I write??
sem_wait(mutex);
lseek(fd, 0, SEEK_SET);
nwrite = write(fd, &c, sizeof(char));
if(nwrite <= 0)
perror("nwrite error");
printf("Father has written (%d byte) %d\n", nwrite, i);
fflush(NULL);
sem_post(mutex);
sem_post(reader); // it's possible to read
}
//wait(NULL);
}
sem_unlink(MUTEX);
sem_unlink(READ);
sem_unlink(WRITE);
//remove(FILENAME);
exit(0);
}
First, you opened the file without specifying an o_flag. That's actually undefined behavior ("Applications shall specify exactly one of .... O_RDONLY .... O_WRONLY .... O_RDWR"), but for practical purposes means the file was opened read only.
Thus the parent's write operation fails with EBADF. Can't write to a read only file!
Second, the child's error checking is incorrect. read() may return zero on success, in which case errno, consulted by perror(), is not guaranteed to be meaningful. You mean to check for a return value of less than zero, not of less than or equal to zero.
Your open() call is opening the file for read only. You have:
fd = open(FILENAME, O_CREAT | O_TRUNC, 0777);
Because you don't explicitly say O_WRONLY or O_RDWR, and because the traditional value for O_RDONLY is 0, you are effectively opening the file read-only.
The 0777 permissions are suspect too. You are not creating an executable; you should not be giving the file executable permissions. In my book, you probably shouldn't be giving others write permission on the file. In fact, I'd probably go with 0600 permissions.
Your program is a bit strange.
First off, you are asking for trouble by having parent and child processes race to be the one to create the target file. It would be better for the parent to create and open the file before forking, and for (only) the child to open it after. Be aware that in that case the child should first close (its copy of) the file descriptor opened by the parent. Alternatively, the way you're doing things, if the parent opened the file then it would probably be sufficient for the child to just use the file descriptor it inherits, without opening the file itself at all.
With that said, it would be more usual for parent and child processes to communicate via a pipe than via a physical file. That has the particular advantage that you do not need to synchronize access via a semaphore; ordinary blocking I/O does the job.
Additionally, I don't see what your mutex semaphore is doing for you. Even with a design that requires you to manually synchronize writing and reading, it looks like your reader and writer semaphores will serve that purpose without help.
Importantly, your parent process is writing in sizeof(char)-byte uints, whereas your child process is trying to read in sizeof(int)-byte units. This is unlikely to have the result you want.
Furthermore, the read() and write() functions may return successfully without having transferred the full number of bytes requested (unless that number is 1 and the file is open in blocking mode). You need to account for that by being prepared to use multiple I/O operations to transfer multi-byte data, if necessary.
Finally, it would be best for just one process to unlink your semaphores. It is ok for that to happen while the other process is still running.

Resources