Application singletons are normally per-userid. Different userids can start the same application and run a singleton application process under that userid. By default, a started application singleton would only connect to any existing application process that runs under the same real userid. An existing application singleton process running under some userid will not prevent a different userid from starting its own singleton process.
It's possible to have a systemwide application singleton, one singleton that spawns a thread and connects to any other userid that starts the same application.
x::singletonapp::instance instance=x::singletonapp::create(factory, 0, 0755);
x::singletonapp::create
() takes two optional
parameters: a system userid, and the permissions for the singleton's
filesystem socket. They default to the real userid of the process that
invoked it, and 0700
, and has the following
effect:
If there's already an existing process running the same application as specified userid, this is the existing singleton process to connect to, to start a new thread.
Otherwise, this is the first singleton process, but if the given real userid is not the invoking process's userid, the singleton cannot be started. The first instance got started under the wrong userid, so an exception gets thrown.
Arrangements must be made, separately, so that the first instance of an application gets started with the proper real userid, otherwise the application singleton cannot be started.
The filesystem mode permissions must reflect whether the singleton accepts connections only from processes with the same userid, or from all userids.
The filesystem socket gets created in a temporary directory whose
default permissions are
0700
, preventing connections from processes that run
under a different userid. For a systemwide singleton, it must specify
permissions of 0755
, in order to accept connections
from processes from all userids. In all cases, even with per-userid
singletons, additional credentials verifications are needed.
validate_peer
() also does a sanity check that the
peer is running the same executable, and not just it's a process with
the same userid.
With systemwide singletons, validate_peer
()
only checks that it's the same executable:
uid_t uid=x::singletonapp::validate_peer(connection, false);
validate_peer
(),
by default, requires that the socket's peer must have the same real userid
as the process that invokes it, otherwise an exception gets thrown.
A single systemwide singleton can spawn threads after other real
userids started the singleton process, so this check gets disabled by
setting the second, optional, parameter to
validate_peer
() to false
.
validate_peer
() returns the peer's system userid,
which can be processed in any application-specific manner.
new_thread
() gets invoked, and the
subsequent thread runs as, using the real userid of the process that
started the singleton process, notwithstanding the userid of the
other singleton process that's connected to the one that's running
the threads.