Saffire relies on the FastCGI (fcgi_stdio
) library and in essence is really easy in setup. The most work is actually
done by daemonizing Saffire so it will run in the background.
The entrypoint is fastcgi_run()
from the src/components/fastcgi/fastcgi_srv.c
file. This will first setup a
listening socket (either a UNIX socket or an IPV4 socket) in setup_socket()
. Then it will drop privileges, as no more
privileges are needed anymore. If Saffire needs to run in the background as a daemon, the daemonize()
function will
be called to do this. Otherwise, it will just initialize the fastcgi system and call the fastcgi_loop()
function.
Scoreboard
The scoreboard is a way to keep track on what’s going on. It’s a bit of shared memory so all workers (if daemonized) can
write their status to it. The scoreboard_dump()
function can dump this information, so you can figure out what is
going on from the command line.
Main loop
The fcgi_loop()
is the main function. First, it will move the socket that is opened for listing to the fastcgi socket.
This way, all data written via the fastcgi library will be automatically passed to the open socket (normally, a webserver
is listening to the other side so it can send the fastcgi data to a connected browser).
We initialize the virtual machine in through vm_init()
with VM_RUNMODE_FASTCGI
. It doesn’t really do much by itself,
but it allows you to check with saffire.sapi()
, and saffire.fastcgi()
for instance.
Since we are running through fastcgi and not on a commandline, writing data to STDIN
, STDOUT
and STDERR
is not
useful. Instead, we redirect all saffire output towards new output helpers called _fcgi_output_char_helper
and
_fcgi_output_string_helper
. These will call FCGX_PutChar
and FCGX_PutStr
instead of fwrite(STDOUT, ..
.
Our main loop will be FCGX_Accept()
, which waits for an incoming connection through FastCGI. It will block until it
receives one. If so, the scoreboard will be changed (number of requests will be increased).
The file we need to run is located in the FastCGI environment called SCRIPT_FILENAME. If found, we load that file (or
its bytecode file), convert to bytecode and create an initial stackframe. That frame will be executed through
vm_execute()
. Once completed, we destroy the frame, codeblock etc. Then we return back to the FCGX_Accept()
loop
again to wait for another connection.