NULL is ambiguous (can be integer and pointer) and using it as
terminator for vararg list of pointers without explicit casting to a
pointer was downright incorrect. nullptr fixes that.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Several headers were no longer needed resp. could be replaced by more
specific ones like noncopyable.hpp.
boost::assign mostly can be replaced with initialization lists and
boost::tuple with std::tuple.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
std::unique_ptr usually can be used instead. std::vector also works
for arrays and even has a data() method as part of the official API in
C++11.
For historic reasons, the functions creating SyncSources returned
plain pointers. We are breaking the API now, so we might as well fix
that.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
We can use std::shared_ptr and std::function instead now.
Lambdas are usually a better alternative to boost/std::bind. The
downside is the need to explicitly specify parameters completely. When
inlining callbacks entirely with lambdas, duplication of that
parameter list can be avoided.
Whenever possible, use std::make_shared to construct objects that are
tracked by std::shared_ptr.
Some objects need a std::weak_ptr during object destruction. For that
we have to use our own implementation of std::enable_shared_from_this,
with a matching creator function. The additional benefit is that we
can get rid of explicit static "create" methods by making that create
function a friend.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Using templates with a varying number of types allows removing
duplicated code for the different cases.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Raising exceptions via throwError() looses the original source code
location information. Fixing that by explicitly passing that
information as additional parameter, created with the preprocessor
macro SE_HERE.
Several files included the complex SyncContext.h only because needed
throwError(). A better place for the revised implementation is the
Exception class which used to be in util.h, now Exception.h.
Simplifying the include statements exposed indirect include
dependencies and removed "using namespace std" from the compilation of
some source files which happened to rely on it. We want to get rid of
that name space polution, so fix the code instead of adding it back.
When using GIO, it is possible to avoid the DBusServer listening on a
publicly accessible address. Connection setup becomes more reliable,
too, because the D-Bus server side can detect that a child died
because the connection will be closed.
When using libdbus, the traditional server/listen and client/connect
model is still used. GDBus GIO mimicks the same API to minimize
changes in ForkExec. The API gets simplified to support both
approaches:
- Choosing an address is no longer possible (was only used in the
test example anyway)
- The new connection callback must be specified already when starting
the server.
The GDBus GIO implementation uses SyncEvolution utility code. Strictly
speaking, this creates a circular dependency
libsyncevolution<->libgdbus. This is solved by not linking libgdbus
against libsyncevolution and expecting executables to do that instead.
The GDBus GIO example no longer linked because of that; it gets removed
because it was of little value.
Now that we started using CLOEXEC, we might as well use it for the
permanent file descriptors created for each ForkExec instance.
Following the boost::instrusive_ptr example and making "add_ref =
true" the default in our CXX GLib and GObject wrappers led to some
memory leaks because it didn't enforce thinking about whether the
plain pointer is already owned by us or not.
It is better to use a mandatory enum value, ADD_REF and TRANSFER_REF,
and force explicit construction. Doing that revealed that the
assignment operator was implemented as constructing a CXX instance
with increased ref count and/or that in some places, a real leak was
caused by increasing the ref count unnecessarily.
Running under valgrind gave a false sense of security. Some of the
real leaks only showed up randomly in tests.
The test covers waiting for a reply that never comes because the peer
dies. GIO D-Bus returns a "connection lost" error in this case. Still
need to test what happens when a process isn't currently waiting for a
response to its own call, but rather a method invocation from its peer
- it seems that it'll simply get stuck waiting forever when the peer
dies.
Delay message processing in the child until m_onConnect is done.
Fixes the following problem with GIO D-Bus:
- client connects, starts helper thread
- parent sends method call
- helper thread processes method calls, discards it
(doesn't match anything)
- client calls m_onConnect (too late)
The introduction of delayed message processing broke the
dbus-client-server, because it does its main work in the onConnect
signal, where replies by the server where not processed after the
change.
The solution is to explicitly allow message processing inside the
signal slot.
The call operator on DBusClientCall[0123] is now blocking. It will
return result values as single value, std::pair or boost::tuple,
respectively. If an error is encountered either locally or in the
peer, a runtime_error is thrown.
This is an API change. The traditional implementation was to start an
asynchronous call. That is still possible, but has to be requested
explicitly with the new start() method.
This distinction is necessary because C++ cannot guess (easily)
whether the callback parameter is a callback type or another parameter
for the D-Bus peer. It's also a bit cleaner in the source code because
now the call operator really acts like a normal, synchronous call.
The downside of the synchronous calls is that complex return values
have to be copied more often. If that is too expensive, then use the
asynchronous start() + callback approach.
Checking authentication needs to be abstraced and cannot be done with
a libdbus-only method. At the moment the assumption is that the
connecting client is at least from the same user.
Methods called from glib C code must not throw exceptions. If that
happens, the problem will be reported via onFailure.
The more likely problem is that the child quits prematurely or with an
error code. Both is reported via onFailure now, so the user of
ForkExecParent no longer has to watch the child itself.
The parameter wasn't really needed for anything. Everything happens
inside the main context and the caller is responsible for creating and
running a loop.
Can run as both client and server. Linked against libsyncevolution
only because it needs some utility methods in it.
Logs authentication state when a new connection is created. Currently
such connections are unauthenticated at first. If the client has the
same user ID as the server, it is allowed to proceed (tested
empirically). If not, authentication fails and handle_message() is
not called (but the connection remains open!?).
Disconnects are not properly detected because GDBus for libdbus
doesn't support reporting disconnects on a connection (not
implemented). Instead of relying on it, better watch child or parent
via some other means. In this example, the server side just keeps
the connection open until the next client connects. The client
lets GDBus exit() the process on disconnect.