0

I'm trying to set up some inter-process communication, and as a first idea I want to use a named pipe to forward messages from one process to the other. The thing I'm getting stuck on is ensuring that the first process only ever writes to the pipe, and the second process only ever reads from the pipe. Now, normally I could just write the program for the first process to only ever write to the pipe, and vice versa for the second process, but I'm somewhat paranoid and want the program to throw an error if it ever even tries to open the pipe in the wrong mode.

Essentially, what I'm trying to do is to "split" the pipe in half, so that the write-end is with my first program:

program1/
├── write-end-of-pipe
└── program1.c

and so that my read-end is with my second program:

program2/
├── read-end-of-pipe
└── program2.c

Ideally there could be actual files on the file system for the read/write ends of the pipe.


Right now, my best solution is the following:

  1. Create a named pipe in program1 and change the file permissions to be write only by this user:

    cd ~/program1
    mkfifo write-end-of-pipe
    chmod 200 write-end-of-pipe
    
  2. Create a named pipe in program2 and change the file permissions to be read only by this user:

    cd ~/program2
    mkfifo read-end-of-pipe
    chmod 400 read-end-of-pipe
    
  3. Create a new user for forwarding, and have it run a daemon that forwards from the first named pipe to the second: (Assuming the user is already created:)

    su - forwarding-daemon-user
    chmod 400 ~/program1/write-end-of-pipe
    chmod 200 ~/program2/read-end-of-pipe
    cat write-end-of-pipe > read-end-of-pipe &
    

The problem I have with this is twofold:

  1. It requires two pipes instead of just one.
  2. It requires a daemon. (My cat command earlier is not robust enough on its own, but it gets the point across.)

Is there a better way to create two files for a pipe, one of which can only be written to, and the other only read?


Edit 1: For some context on what I want to use this inter-process communication for: I think it would be cool if I could have a "screen-share" where one process written in one language creates a screen (essentially a video stream), and another process in an entirely different language displays the screen it receives. (Example use case: One language makes it easy to render a game, but you want to write your GUI in another language.) The reason for my paranoia about reading/writing is that I want to be able to swap out different programs that create screens or view screens, and I don't want to worry about connecting two screen creators together (if I provide a read end and a write end, then one program gets the wrong end if I make such a mistake, and the error is caught immediately instead of later when a pipe overflows) or otherwise broken programs causing silent problems.

Edit 2: I feel like I should give an explanation why having two separate users for the reading/writing is not an ideal solution for me. The main reason is that it is a significant step on the path towards containerization. Once you say, "I'll just control permissions via separate users/namespaces," you need to figure out how you are going to set up those users/namespaces, and that essentially means putting the program in a container. I want to avoid this because it's not as flexible; suddenly every program now needs a standardized way of being invoked, the named pipe connecting the two programs needs to be created by a special user that can peer into these containers, etc.

Hence, I would prefer to avoid multiple users, and similar techniques that require wrapping the program to be called. A solution that would work well would be if there was some way to "mount" the named pipe so that it has two different file permissions from the two different locations to be written to/read from, but I don't think this is possible on Linux.

4
  • The traditional way to separate read/write permissions is by users/groups. Have one user/group be allowed to write, and another allowed to read. Run the read-end programs with the latter, and write-end programs with the former. No need for separate files. Commented Feb 28 at 7:00
  • <s>Right, this is the traditional way. But I really want the same user to be running both programs.</s> Actually, looking into it more this might be the solution for me. Thanks! Commented Feb 28 at 7:07
  • Alright, I've looked into it significantly more and it's not really a solution I'm happy with (but thank you for pointing it out anyways). I would be very happy to hear other solutions! Commented Feb 28 at 7:34
  • 1
    Side note: there is no need to reinvent the revision history in the body of the question. Commented Feb 28 at 22:39

2 Answers 2

5

If I absolutely wanted to ensure that I couldn't get a double write or double read situation, I would just change to using sockets (either TCP or UNIX).

Lets say the the writing program is going to create the listening socket. Only one process can bind a port, so that prevents a second writer.

The writer will have to accept() the incoming connection and you can simply implement logic so it won't accept a second connection, until the first connection terminates - hence preventing a double read scenario.


TL;DR - FIFOs are fine for throwing something together quickly, but for a robust solution, I would ignore them.

On the other hand you have to ask "is this a real problem"? The cost of the problem occurring/cost to fix is so minimal it's probably not worth my time to prevent it.

However using TCP sockets gives me the flexibility to run the reader and writer on different machines, that's something I often find very useful (for debugging etc) even when the final production deployment will always be on a single machine.

2
├── write-end-of-pipe
├── read-end-of-pipe

Nope, not happening with named pipes. Their point is that they are the same "visible name" for both ends.

So, wrong technology if that's what you want.

For truly unidirectional communications with file access semantics, you could let the two processes connect via a two-directional UNIX socket¹. You could have the processes use pipe to open pipes, close the end they don't want to exist, and send over the file descriptors through the socket.

Another option is to create the named pipe, let the first program open it in the mode it needs, and change the permission for the same user to be "read-only" or "write-only". That doesn't affect file descriptors obtained through opening before the permission change, so the program continues to work, but makes it impossible for the "later" program to access the file in the wrong mode. However, this has an obvious temporal race condition.

For simple unidirectional communications: UDP sockets would work. You can simply just let the receiving end of communications listen on a port, and the other can send.


¹ TCP won't work here, because you need to exchange file descriptors

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.