Maybe FIFO

This post concerns using a FIFO on unix for notifications from a command line to to a service bot. The maybe part is that we have a reader (the bot) that will mostly be doing other things, and a writer that will make a best effort but will not block. The default for FIFOs is to block, a lot, which does not work here. If a message fails we do want alerts to stderr and possibly also to syslog, so that afterwards there are indications of what failed and when.

File permissions (and those of any parent directories) should be restricted by default, or custom groups used to limit who can talk to what, the group advice coming with the caveat that certain daemons have a habit of dropping secondary groups by default. Restricted permissions will help prevent malicious or annoying users from playing around with the FIFO.

Reader Implementation

This part reads from the FIFO, non-blocking. There is not an event loop as the actual code is part of a libircclient bot, so the read happens now and then in a thread that also carries out other checks. If you do have libevent or some other fancy I/O library, then the FIFO should ideally be integrated into that.

reader1.c

yadda.h

A bummer is that the FIFO is busy-checked. Not often, but too much given the desire for quick enough notifications versus the fact that the notifications happen somewhere between zero to only a few times per day. This portion of the code should block and only run when there are bytes to read. However, the entire process cannot be blocked as the process must respond to IRC PING messages, among other tasks. One option would be to integrate the libircclient code into an event system, but that would require learning more about the low-level details of libircclient instead of leaning on the event loop that libircclient provides. Yet another would be to replace libircclient with enough string handling for the IRC protocol to work in an event system. A third option would be to add a third thread (one is already running the libircclient loop, and another is performing periodic monitoring checks) that does block until the FIFO has bytes to read. A concern is whether the libircclient routines used are thread safe, or whether the various threads will need to use locks to avoid conflicting with one another. And that blocking I/O can be put into a random thread without problems, like, with signals?

Writer Implementation

This is a tool that writes a message to the reader. Longer messages would run into IRC length limits, and anyways notifications (unlike certain blog posts) should be short and to the point. A postcard is not an appropriate medium for a dissertation. No attempt at locking is made as the notifications will be both infrequent and short enough that the writes should send a complete message in one go. Hopefully. Also the messages are saved "somewhere" after the writer exits; this somewhere is doubtless limited and may result in messages being lost, or new messages failing to post if the reader does not drain that somewhere soon enough. Or you could run the kernel out of memory and the system may crash. Hopefully you don't have one of those kernels.

writer1.c

A URL shortener may be necessary if a tool generates notification URL that are too long, and you cannot fix that tool to send something shorter. This involves reading the too-long input, obtaining a shorter link that redirects to the original, then sending the shorter link through the message system. There are various problems with this, like not knowing where links go (did someone submit a phishing link?) and all the extra complexity involved. I mention this because overly long URL do exist and you may need to deal with them. Overly long URL for the old web wrapped in a blob of JavaScript that generates a button to click on? Burn it with fire.

A known FIFO file location should be compiled into the notification tool so that it does not need to be specified, just the message to write. Or, an alias could be written that includes the right FIFO, but then you need to remember to have and use that correct alias.

Some Random Testing

What happens when the reader blocks for too long, and too much data is stuffed into the FIFO by a writer? For this the sleep(3) delay in reader1.c might be increased, and a custom client used to write a lot of bytes.

For a test client we want something easy to fiddle around with, but also low-level enough so that specific return values from specific system calls can be called out, rather than as abstracted through a higher level I/O system that may well hide such details. On embiggened systems the defaults may need to be embiggened to account for embiggened buffers on such systems, or you could use a binary search to look around for the limits automatically, but that's more work.

First up, the 99999 has run into the default buffer size and failed. This will vary depending on how embiggened the buffers are on your system. With multiple clients writing such large messages there would definitely be a risk of corrupted input, as client A could write 39299 of some larger message, then client B might write something, and, lo, mixed messages seen by the reader.

Some tweaks later (I'm making this up as I go along) and the script is now:

Which results in the non-blocking I/O bouncing off of the sleeping reader:

It may also be instructive to see what happens when the writer uses blocking I/O.

../04/fifofum.gmi