Server

Server provide HTTP technologies integrations under a common interface. They inherit from GLib.Application, providing an optimal integration with the host environment.

General

Basically, you have access to a DBusConnection to communicate with other process and a GLib.MainLoop to process events and asynchronous work.

  • an application id to identify primary instance
  • startup signal emmited right after the registration
  • shutdown signal just before the server exits
  • a resource base path
  • ability to handle CLI arguments

The server can be gracefully terminated by sending a SIGTERM signal to the process.

Load an implementation

Server implementations are dynamically loaded using GLib.Module. It makes it possible to define its own implementation if necessary.

The shared library name must conform to libvsgi-<name> with the appropriate extension. For instance, on GNU/Linux, the CGI module is stored in ${LIBDIR}/vsgi/servers/libvsgi-cgi.so.

To load an implementation, use the Server.new factory, which can receive GObject-style arguments as well.

var cgi_server = Server.new ("cgi", "application-id", "org.valum.example.CGI");

if (cgi_server == null) {
    assert_not_reached ();
}

cgi_server.set_application_callback ((req, res) => {
    return res.expand_utf8 ("Hello world!");
});

For typical case, use Server.new_with_application to initialize the instance with an application identifier and callback:

var cgi_server = Server.new_with_application ("cgi", "org.example.CGI", (req, res) => {
    return true;
});

For more flexibility, the ServerModule class allow a more fine-grained control for loading a server implementation. If non-null, the directory property will be used to retrieve the implementation from the given path instead of standard locations.

The computed path of the shared library is available from path property, which can be used for debugging purposes.

var directory  = "/usr/lib64/vsgi/servers";
var cgi_module = new ServerModule (directory, "cgi");

if (!cgi_module.load ()) {
    error ("could not load 'cgi' from '%s'", cgi_module.path);
}

var server = Object.new (cgi_module.server_type);

Unloading a module is not necessary: once initially loaded, a use count is kept so that it can be loaded on need or unloaded if not used.

Warning

Since a ServerModule cannot be disposed (see GLib.TypeModule), one must be careful of how its reference is being handled. For instance, Server.new keeps track of requested implementations and persist them forever.

Mixing direct usages of ServerModule and Server.@new (and the likes) is not recommended and will result in undefined behaviours if an implementation is loaded more than once.

DBus connection

GLib.Application will automatically register to the session DBus bus, making IPC (Inter-Process Communication) an easy thing.

It can be used to expose runtime information such as a database connection details or the amount of processing requests. See this example of DBus server for code examples.

This can be used to request services, communicate between your workers and interact with the runtime.

var connection = server.get_dbus_connection ()

connection.call ()

Options

Each server implementation can optionally take arguments that parametrize its runtime.

If you build your application in a main block, it will not be possible to obtain the CLI arguments to parametrize the runtime. Instead, the code can be written in a usual main function.

public static int main (string[] args) {
    Server.new ("http", "org.vsgi.App", (req, res) => {
        res.status = Soup.Status.OK;
        return res.body.write_all ("Hello world!".data, null);
    }).run (args);
}

If you specify the --help flag, you can get more information on the available options which vary from an implementation to another.

build/examples/fastcgi --help
Usage:
  fastcgi [OPTION...]

Help Options:
  -h, --help                  Show help options
  --help-all                  Show all help options
  --help-gapplication         Show GApplication options

Application Options:
  --forks=0                   Number of fork to create
  -s, --socket                Listen to the provided UNIX domain socket (or named pipe for WinNT)
  -p, --port                  Listen to the provided TCP port
  -f, --file-descriptor=0     Listen to the provided file descriptor
  -b, --backlog=10            Listen queue depth used in the listen() call

Forking

To achieve optimal performances on a multi-core architecture, VSGI support forking at the server level.

Warning

Keep in mind that the fork system call will actually copy the whole process: no resources (e.g. lock, memory) can be shared unless inter-process communication is used.

The --forks option will spawn the requested amount of workers, which should optimally default to the number of available CPUs.

server.run ("app", {"--forks=4"});

It’s also possible to fork manually via the fork call.

using VSGI.HTTP;

var server = new Server ();

server.listen (options);
server.fork ();

new MainLoop ().run ();

It is recommended to fork only through that call since implementations such as CGI are not guaranteed to support it.

Listen on distinct interfaces

Typically, fork is called after listen so that all processes share the same file descriptors and interfaces. However, it might be useful to listen to multiple ports (e.g. HTTP and HTTPS).

using VSGI.HTTP;

var server = new Server ();

var parent_options = new VariantDict ();
var child_options = new VariantDict ();

// parent serve HTTP
parent_options.insert_value ("port", new Variant.int32 (80));

// child serve HTTPS
child_options.insert_value ("https");
child_options.insert_value ("port", new Variant.int32 (443));

if (server.fork () > 0) {
    server.listen (parent_options);
} else {
    server.listen (child_options);
}

new MainLoop ().run ();