SAPI - FastCGI

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.