syncevolution/src/syncevo/LocalTransportAgent.cpp

1212 lines
47 KiB
C++
Raw Normal View History

support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
/*
* Copyright (C) 2010 Patrick Ohly
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <syncevo/LocalTransportAgent.h>
#include <syncevo/SyncContext.h>
#include <syncevo/SyncML.h>
#include <syncevo/LogRedirect.h>
#include <syncevo/StringDataBlob.h>
#include <syncevo/IniConfigNode.h>
#include <syncevo/GLibSupport.h>
#include <syncevo/DBusTraits.h>
#include <syncevo/SuspendFlags.h>
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
#include <syncevo/LogRedirect.h>
#include <syncevo/LogDLT.h>
#include <syncevo/BoostHelper.h>
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
#include <synthesis/syerror.h>
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
#include <stddef.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pcrecpp.h>
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
#include <algorithm>
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
#include <syncevo/declarations.h>
SE_BEGIN_CXX
class NoopAgentDestructor
{
public:
void operator () (TransportAgent *agent) throw() {}
};
LocalTransportAgent::LocalTransportAgent(SyncContext *server,
const std::string &clientConfig,
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
void *loop) :
m_server(server),
m_clientConfig(SyncConfig::normalizeConfigString(clientConfig)),
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
m_status(INACTIVE),
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_loop(loop ?
GMainLoopCXX(static_cast<GMainLoop *>(loop), ADD_REF) :
GMainLoopCXX(g_main_loop_new(NULL, false), TRANSFER_REF))
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
{
}
boost::shared_ptr<LocalTransportAgent> LocalTransportAgent::create(SyncContext *server,
const std::string &clientConfig,
void *loop)
{
boost::shared_ptr<LocalTransportAgent> self(new LocalTransportAgent(server, clientConfig, loop));
self->m_self = self;
return self;
}
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
LocalTransportAgent::~LocalTransportAgent()
{
}
void LocalTransportAgent::start()
{
// TODO (?): check that there are no conflicts between the active
// sources. The old "contexts must be different" check achieved that
// via brute force (because by definition, databases from different
// contexts are meant to be independent), but it was too coarse
// and ruled out valid configurations.
// if (m_clientContext == m_server->getContextName()) {
// SE_THROW(StringPrintf("invalid local sync inside context '%s', need second context with different databases", context.c_str()));
// }
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_forkexec) {
SE_THROW("local transport already started");
}
m_status = ACTIVE;
m_forkexec = ForkExecParent::create("syncevo-local-sync");
#ifdef USE_DLT
if (getenv("SYNCEVOLUTION_USE_DLT")) {
m_forkexec->addEnvVar("SYNCEVOLUTION_USE_DLT", StringPrintf("%d", LoggerDLT::getCurrentDLTLogLevel()));
}
#endif
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_forkexec->m_onConnect.connect(boost::bind(&LocalTransportAgent::onChildConnect, this, _1));
// fatal problems, including quitting child with non-zero status
m_forkexec->m_onFailure.connect(boost::bind(&LocalTransportAgent::onFailure, this, _2));
// watch onQuit and remember whether the child is still running,
// because it might quit prematurely with a zero return code (for
// example, when an unexpected slow sync is detected)
m_forkexec->m_onQuit.connect(boost::bind(&LocalTransportAgent::onChildQuit, this, _1));
m_forkexec->start();
}
/**
* Uses the D-Bus API provided by LocalTransportParent.
*/
class LocalTransportParent : private GDBusCXX::DBusRemoteObject
{
public:
static const char *path() { return "/"; }
static const char *interface() { return "org.syncevolution.localtransport.parent"; }
static const char *destination() { return "local.destination"; }
static const char *askPasswordName() { return "AskPassword"; }
static const char *storeSyncReportName() { return "StoreSyncReport"; }
LocalTransportParent(const GDBusCXX::DBusConnectionPtr &conn) :
GDBusCXX::DBusRemoteObject(conn, path(), interface(), destination()),
m_askPassword(*this, askPasswordName()),
m_storeSyncReport(*this, storeSyncReportName())
{}
/** LocalTransportAgent::askPassword() */
GDBusCXX::DBusClientCall1<std::string> m_askPassword;
/** LocalTransportAgent::storeSyncReport() */
GDBusCXX::DBusClientCall0 m_storeSyncReport;
};
/**
* Uses the D-Bus API provided by LocalTransportAgentChild.
*/
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
class LocalTransportChild : public GDBusCXX::DBusRemoteObject
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
{
public:
static const char *path() { return "/"; }
static const char *interface() { return "org.syncevolution.localtransport.child"; }
static const char *destination() { return "local.destination"; }
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
static const char *logOutputName() { return "LogOutput"; }
static const char *setFreezeName() { return "SetFreeze"; }
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
static const char *startSyncName() { return "StartSync"; }
static const char *sendMsgName() { return "SendMsg"; }
LocalTransportChild(const GDBusCXX::DBusConnectionPtr &conn) :
GDBusCXX::DBusRemoteObject(conn, path(), interface(), destination()),
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
m_logOutput(*this, logOutputName(), false),
m_setFreeze(*this, setFreezeName()),
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_startSync(*this, startSyncName()),
m_sendMsg(*this, sendMsgName())
{}
/**
* information from server config about active sources:
* mapping is from server source names to child source name + sync mode
* (again as set on the server side!)
*/
typedef std::map<std::string, StringPair> ActiveSources_t;
/** use this to send a message back from child to parent */
typedef boost::shared_ptr< GDBusCXX::Result2< std::string, GDBusCXX::DBusArray<uint8_t> > > ReplyPtr;
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
/** log output with level and message; process name will be added by parent */
GDBusCXX::SignalWatch2<string, string> m_logOutput;
/** LocalTransportAgentChild::setFreeze() */
GDBusCXX::DBusClientCall0 m_setFreeze;
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/** LocalTransportAgentChild::startSync() */
GDBusCXX::DBusClientCall2<std::string, GDBusCXX::DBusArray<uint8_t> > m_startSync;
/** LocalTransportAgentChild::sendMsg() */
GDBusCXX::DBusClientCall2<std::string, GDBusCXX::DBusArray<uint8_t> > m_sendMsg;
};
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
void LocalTransportAgent::logChildOutput(const std::string &level, const std::string &message)
{
Logger::MessageOptions options(Logger::strToLevel(level.c_str()));
options.m_processName = &m_clientConfig;
// Child should have written this into its own log file and/or syslog/dlt already.
// Only pass it on to a user of the command line interface.
options.m_flags = Logger::MessageOptions::ALREADY_LOGGED;
SyncEvo::Logger::instance().messageWithOptions(options, "%s", message.c_str());
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::onChildConnect(const GDBusCXX::DBusConnectionPtr &conn)
{
SE_LOG_DEBUG(NULL, "child is ready");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_parent.reset(new GDBusCXX::DBusObjectHelper(conn,
LocalTransportParent::path(),
LocalTransportParent::interface(),
GDBusCXX::DBusObjectHelper::Callback_t(),
true));
m_parent->add(this, &LocalTransportAgent::askPassword, LocalTransportParent::askPasswordName());
m_parent->add(this, &LocalTransportAgent::storeSyncReport, LocalTransportParent::storeSyncReportName());
m_parent->activate();
m_child.reset(new LocalTransportChild(conn));
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
m_child->m_logOutput.activate(boost::bind(&LocalTransportAgent::logChildOutput, this, _1, _2));
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// now tell child what to do
LocalTransportChild::ActiveSources_t sources;
BOOST_FOREACH(const string &sourceName, m_server->getSyncSources()) {
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
SyncSourceNodes nodes = m_server->getSyncSourceNodesNoTracking(sourceName);
SyncSourceConfig source(sourceName, nodes);
std::string sync = source.getSync();
if (sync != "disabled") {
string targetName = source.getURINonEmpty();
sources[sourceName] = std::make_pair(targetName, sync);
}
}
m_child->m_startSync.start(m_clientConfig,
StringPair(m_server->getConfigName(),
m_server->isEphemeral() ?
"ephemeral" :
m_server->getRootPath()),
static_cast<std::string>(m_server->getLogDir()),
m_server->getDoLogging(),
std::make_pair(m_server->getSyncUser(),
m_server->getSyncPassword()),
m_server->getConfigProps(),
sources,
boost::bind(&LocalTransportAgent::storeReplyMsg, m_self, _1, _2, _3));
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
void LocalTransportAgent::onFailure(const std::string &error)
{
m_status = FAILED;
g_main_loop_quit(m_loop.get());
SE_LOG_ERROR(NULL, "local transport failed: %s", error.c_str());
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_parent.reset();
m_child.reset();
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::onChildQuit(int status)
{
SE_LOG_DEBUG(NULL, "child process has quit with status %d", status);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
g_main_loop_quit(m_loop.get());
}
static void GotPassword(const boost::shared_ptr< GDBusCXX::Result1<const std::string &> > &reply,
const std::string &password)
{
reply->done(password);
}
static void PasswordException(const boost::shared_ptr< GDBusCXX::Result1<const std::string &> > &reply)
{
// TODO: refactor, this is the same as dbusErrorCallback
try {
// If there is no pending exception, the process will abort
// with "terminate called without an active exception";
// dbusErrorCallback() should only be called when there is
// a pending exception.
// TODO: catch this misuse in a better way
throw;
} catch (...) {
// let D-Bus parent log the error
std::string explanation;
Exception::handle(explanation, HANDLE_EXCEPTION_NO_ERROR);
reply->failed(GDBusCXX::dbus_error("org.syncevolution.localtransport.error", explanation));
}
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::askPassword(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
const boost::shared_ptr< GDBusCXX::Result1<const std::string &> > &reply)
{
// pass that work to our own SyncContext and its UI - currently blocks
SE_LOG_DEBUG(NULL, "local sync parent: asked for password %s, %s",
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
passwordName.c_str(),
descr.c_str());
try {
if (m_server) {
m_server->getUserInterfaceNonNull().askPasswordAsync(passwordName, descr, key,
// TODO refactor: use dbus-callbacks.h
boost::bind(GotPassword,
reply,
_1),
boost::bind(PasswordException,
reply));
} else {
SE_LOG_DEBUG(NULL, "local sync parent: password request failed because no m_server");
reply->failed(GDBusCXX::dbus_error("org.syncevolution.localtransport.error",
"not connected to UI"));
}
} catch (...) {
PasswordException(reply);
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
void LocalTransportAgent::storeSyncReport(const std::string &report)
{
SE_LOG_DEBUG(NULL, "got child sync report:\n%s",
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
report.c_str());
m_clientReport = SyncReport(report);
}
void LocalTransportAgent::getClientSyncReport(SyncReport &report)
{
report = m_clientReport;
}
void LocalTransportAgent::setContentType(const std::string &type)
{
m_contentType = type;
}
// workaround for limitations of bind+signals when used together with plain GMainLoop pointer
// (pointer to undefined struct)
static void gMainLoopQuit(GMainLoopCXX *loop)
{
g_main_loop_quit(loop->get());
}
void LocalTransportAgent::shutdown()
{
SE_LOG_DEBUG(NULL, "parent is shutting down");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_forkexec) {
// block until child is done
boost::signals2::scoped_connection c(m_forkexec->m_onQuit.connect(boost::bind(gMainLoopQuit,
&m_loop)));
local sync: kill syncevo-local-sync with SIGTERM Shutting down syncevo-local-sync in a timely manner when aborting is hard: the process might be stuck in a blocking call which cannot be made to check the abort request (blocking libneon, activesyncd client library, ...). The best that can be done is to let the process be killed by the SIGTERM. To have some trace of that, catch the signal and log the signal; there's a slight risk that the logging system is in an inconsistent state, but overall that risk is minor. Because syncevo-local-sync catches SIGINT, ForkExec::stop() must send SIGTERM in addition to SIGINT. To suppress redundant and misleading ERROR messages when the bad child status is handled, the ForkExecParent remembers that itself asked the child to stop and only treats unexpected "killed by signal" results as error. The local transport must call that stop() in its cancel(). It enters the "canceled" state which prevents all further communication with the child, in particular waiting for the child sync report; doing that would produce another redundant error message about "child exited without sending report". Calling stop() in the local transport's shutdown() is no longer possible, because it would kill the child right away. Before it simply had no effect, because SIGINT was ignored. This points towards an unsolved problem: how long should the parent wait for the child after the sync is done? If the child gets stuck hard after sending its last message, the parent currently waits forever until the user aborts. In the sync event loop the caller of the transport must recognize CANCELED as something which might be desired and thus should not be logged as ERROR. That way the Synthesis engine is called one more time with STEPCMD_ABORT also in those cases where the transport itself detected the abort request first.
2012-01-20 15:28:54 +01:00
// don't kill the child here - we expect it to complete by
// itself at some point
// TODO: how do we detect a child which gets stuck after its last
// communication with the parent?
// m_forkexec->stop();
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
while (m_forkexec->getState() != ForkExecParent::TERMINATED) {
SE_LOG_DEBUG(NULL, "waiting for child to stop");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
g_main_loop_run(m_loop.get());
}
m_forkexec.reset();
m_parent.reset();
m_child.reset();
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
void LocalTransportAgent::setFreeze(bool freeze)
{
// Relay to other side, check for error exception synchronously.
if (m_child) {
m_child->m_setFreeze(freeze);
}
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::send(const char *data, size_t len)
{
if (m_child) {
m_status = ACTIVE;
m_child->m_sendMsg.start(m_contentType, GDBusCXX::makeDBusArray(len, (uint8_t *)(data)),
boost::bind(&LocalTransportAgent::storeReplyMsg, m_self, _1, _2, _3));
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
} else {
m_status = FAILED;
SE_THROW_EXCEPTION(TransportException,
"cannot send message because child process is gone");
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::storeReplyMsg(const std::string &contentType,
const GDBusCXX::DBusArray<uint8_t> &reply,
const std::string &error)
{
m_replyMsg.assign(reinterpret_cast<const char *>(reply.second),
reply.first);
m_replyContentType = contentType;
if (error.empty()) {
m_status = GOT_REPLY;
} else {
// Only an error if the client hasn't shut down normally.
if (m_clientReport.empty()) {
SE_LOG_ERROR(NULL, "sending message to child failed: %s", error.c_str());
m_status = FAILED;
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
g_main_loop_quit(m_loop.get());
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::cancel()
{
local sync: kill syncevo-local-sync with SIGTERM Shutting down syncevo-local-sync in a timely manner when aborting is hard: the process might be stuck in a blocking call which cannot be made to check the abort request (blocking libneon, activesyncd client library, ...). The best that can be done is to let the process be killed by the SIGTERM. To have some trace of that, catch the signal and log the signal; there's a slight risk that the logging system is in an inconsistent state, but overall that risk is minor. Because syncevo-local-sync catches SIGINT, ForkExec::stop() must send SIGTERM in addition to SIGINT. To suppress redundant and misleading ERROR messages when the bad child status is handled, the ForkExecParent remembers that itself asked the child to stop and only treats unexpected "killed by signal" results as error. The local transport must call that stop() in its cancel(). It enters the "canceled" state which prevents all further communication with the child, in particular waiting for the child sync report; doing that would produce another redundant error message about "child exited without sending report". Calling stop() in the local transport's shutdown() is no longer possible, because it would kill the child right away. Before it simply had no effect, because SIGINT was ignored. This points towards an unsolved problem: how long should the parent wait for the child after the sync is done? If the child gets stuck hard after sending its last message, the parent currently waits forever until the user aborts. In the sync event loop the caller of the transport must recognize CANCELED as something which might be desired and thus should not be logged as ERROR. That way the Synthesis engine is called one more time with STEPCMD_ABORT also in those cases where the transport itself detected the abort request first.
2012-01-20 15:28:54 +01:00
if (m_forkexec) {
SE_LOG_DEBUG(NULL, "killing local transport child in cancel()");
local sync: kill syncevo-local-sync with SIGTERM Shutting down syncevo-local-sync in a timely manner when aborting is hard: the process might be stuck in a blocking call which cannot be made to check the abort request (blocking libneon, activesyncd client library, ...). The best that can be done is to let the process be killed by the SIGTERM. To have some trace of that, catch the signal and log the signal; there's a slight risk that the logging system is in an inconsistent state, but overall that risk is minor. Because syncevo-local-sync catches SIGINT, ForkExec::stop() must send SIGTERM in addition to SIGINT. To suppress redundant and misleading ERROR messages when the bad child status is handled, the ForkExecParent remembers that itself asked the child to stop and only treats unexpected "killed by signal" results as error. The local transport must call that stop() in its cancel(). It enters the "canceled" state which prevents all further communication with the child, in particular waiting for the child sync report; doing that would produce another redundant error message about "child exited without sending report". Calling stop() in the local transport's shutdown() is no longer possible, because it would kill the child right away. Before it simply had no effect, because SIGINT was ignored. This points towards an unsolved problem: how long should the parent wait for the child after the sync is done? If the child gets stuck hard after sending its last message, the parent currently waits forever until the user aborts. In the sync event loop the caller of the transport must recognize CANCELED as something which might be desired and thus should not be logged as ERROR. That way the Synthesis engine is called one more time with STEPCMD_ABORT also in those cases where the transport itself detected the abort request first.
2012-01-20 15:28:54 +01:00
m_forkexec->stop();
}
m_status = CANCELED;
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
TransportAgent::Status LocalTransportAgent::wait(bool noReply)
{
if (m_status == ACTIVE) {
// need next message; for noReply == true we are done
if (noReply) {
m_status = INACTIVE;
} else {
while (m_status == ACTIVE) {
SE_LOG_DEBUG(NULL, "waiting for child to send message");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_forkexec &&
m_forkexec->getState() == ForkExecParent::TERMINATED) {
m_status = FAILED;
if (m_clientReport.getStatus() != STATUS_OK &&
m_clientReport.getStatus() != STATUS_HTTP_OK) {
// Report that status, with an error message which contains the explanation
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
// added to the client's error. We are a bit fuzzy about matching the status:
// 10xxx matches xxx and vice versa.
int status = m_clientReport.getStatus();
if (status >= sysync::LOCAL_STATUS_CODE && status <= sysync::LOCAL_STATUS_CODE_END) {
status -= sysync::LOCAL_STATUS_CODE;
}
std::string explanation = StringPrintf("failure on target side %s of local sync",
m_clientConfig.c_str());
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
static const pcrecpp::RE re("\\((?:local|remote), status (\\d+)\\): (.*)");
int clientStatus;
std::string clientExplanation;
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
if (re.PartialMatch(m_clientReport.getError(), &clientStatus, &clientExplanation) &&
(status == clientStatus ||
status == clientStatus - sysync::LOCAL_STATUS_CODE)) {
explanation += ": ";
explanation += clientExplanation;
}
SE_THROW_EXCEPTION_STATUS(StatusException,
explanation,
m_clientReport.getStatus());
} else {
SE_THROW_EXCEPTION(TransportException,
"child process quit without sending its message");
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
g_main_loop_run(m_loop.get());
}
}
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
return m_status;
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::getReply(const char *&data, size_t &len, std::string &contentType)
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
{
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_status != GOT_REPLY) {
SE_THROW("internal error, no reply available");
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
contentType = m_replyContentType;
data = m_replyMsg.c_str();
len = m_replyMsg.size();
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void LocalTransportAgent::setTimeout(int seconds)
{
// setTimeout() was meant for unreliable transports like HTTP
// which cannot determine whether the peer is still alive. The
// LocalTransportAgent uses sockets and will notice when a peer
// dies unexpectedly, so timeouts should never be necessary.
//
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// Quite the opposite, because the "client" in a local sync
// with WebDAV on the client side can be quite slow, incorrect
// timeouts were seen where the client side took longer than
// the default timeout of 5 minutes to process a message and
// send a reply.
//
// Therefore we ignore the request to set a timeout here and thus
// local send/receive operations are allowed to continue for as
// long as they like.
//
// m_timeoutSeconds = seconds;
}
class LocalTransportUI : public UserInterface
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
{
boost::shared_ptr<LocalTransportParent> m_parent;
public:
LocalTransportUI(const boost::shared_ptr<LocalTransportParent> &parent) :
m_parent(parent)
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
{}
/** implements password request by asking the parent via D-Bus */
password handling: fixed KWallet support, global configuration option KWallet support was broken: syncevo-dbus-server checked KDE_FULL_SESSION to determine whether it should use KWallet instead of GNOME Keyring. That did not work, because the env variable was not set for D-Bus daemons. Automatically detecting KDE users is not possible at the moment. Instead KDE users have to manually set the new "keyring" global config property to "KDE" (case insensitive) if the SyncEvolution installation supports both, because GNOME Keyring is the default to avoid surprises for traditional users. If only KWallet support is enabled, then this is not necessary. "GNOME" and "true/false/1/0/yes/no" can also be set. This has the advantage that keyring usage can be enabled permanently for the command line in --daemon=no mode; normally keyrings are not used in that mode because accessing them can bring up UI dialogs. It also becomes possible to disable keyring usage in syncevo-dbus-server, something which couldn't be done before. The --keyring command line option is still supported, as an alias for "[--sync-property] keyring=<value>". The default value for --keyring is true, to match the traditional behavior. In contrast to other sync properties, setting "keyring" does not require an explicit --run parameter. Again this is done to mirror traditional usage. Reading a password also (unintentionally) checked all supported storages while searching for the password. Now it uses exactly one storage and falls back to asking for the password directly. The commit itself also cleans up the code a bit (reformatted, fixed comments). Choosing the right slot in the password signals is done via a new InitStateTri parameter which contains the "keyring" setting. Error checking (unsupported keyring string, --keyring=yes and no keyring enabled) is done in additional slots which run after all the regular ones. Parameter parsing for --sync and --keyring were unified. However, there is the difference that --keyring has an implicit default value ("yes") and never has an additional parameter, in contrast to --sync, which always is followed by one. The new CmdlineTest::testKeyring covers different ways of using --keyring. It relies on actually invoking keyring backends, something not done by the default SyncContext UI. Therefore CmdlineSyncClient+KeyringSyncCmdline were moved into libsyncevolution, to be used by CmdlineTest.
2012-05-29 18:14:13 +02:00
virtual string askPassword(const string &passwordName,
const string &descr,
const ConfigPasswordKey &key)
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
{
SE_LOG_DEBUG(NULL, "local transport child: requesting password %s, %s via D-Bus",
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
passwordName.c_str(),
descr.c_str());
std::string password;
std::string error;
bool havePassword = false;
m_parent->m_askPassword.start(passwordName, descr, key,
boost::bind(&LocalTransportUI::storePassword, this,
boost::ref(password), boost::ref(error),
boost::ref(havePassword),
_1, _2));
SuspendFlags &s = SuspendFlags::getSuspendFlags();
while (!havePassword) {
if (s.getState() != SuspendFlags::NORMAL) {
SE_THROW_EXCEPTION_STATUS(StatusException,
StringPrintf("User did not provide the '%s' password.",
passwordName.c_str()),
SyncMLStatus(sysync::LOCERR_USERABORT));
}
g_main_context_iteration(NULL, true);
}
if (!error.empty()) {
Exception::tryRethrowDBus(error);
SE_THROW(StringPrintf("retrieving password failed: %s", error.c_str()));
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
return password;
}
virtual bool savePassword(const std::string &passwordName, const std::string &password, const ConfigPasswordKey &key) { SE_THROW("not implemented"); return false; }
virtual void readStdin(std::string &content) { SE_THROW("not implemented"); }
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
private:
void storePassword(std::string &res, std::string &errorRes, bool &haveRes, const std::string &password, const std::string &error)
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
{
if (!error.empty()) {
SE_LOG_DEBUG(NULL, "local transport child: D-Bus password request failed: %s",
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
error.c_str());
errorRes = error;
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
} else {
SE_LOG_DEBUG(NULL, "local transport child: D-Bus password request succeeded");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
res = password;
}
haveRes = true;
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
};
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
local sync: kill syncevo-local-sync with SIGTERM Shutting down syncevo-local-sync in a timely manner when aborting is hard: the process might be stuck in a blocking call which cannot be made to check the abort request (blocking libneon, activesyncd client library, ...). The best that can be done is to let the process be killed by the SIGTERM. To have some trace of that, catch the signal and log the signal; there's a slight risk that the logging system is in an inconsistent state, but overall that risk is minor. Because syncevo-local-sync catches SIGINT, ForkExec::stop() must send SIGTERM in addition to SIGINT. To suppress redundant and misleading ERROR messages when the bad child status is handled, the ForkExecParent remembers that itself asked the child to stop and only treats unexpected "killed by signal" results as error. The local transport must call that stop() in its cancel(). It enters the "canceled" state which prevents all further communication with the child, in particular waiting for the child sync report; doing that would produce another redundant error message about "child exited without sending report". Calling stop() in the local transport's shutdown() is no longer possible, because it would kill the child right away. Before it simply had no effect, because SIGINT was ignored. This points towards an unsolved problem: how long should the parent wait for the child after the sync is done? If the child gets stuck hard after sending its last message, the parent currently waits forever until the user aborts. In the sync event loop the caller of the transport must recognize CANCELED as something which might be desired and thus should not be logged as ERROR. That way the Synthesis engine is called one more time with STEPCMD_ABORT also in those cases where the transport itself detected the abort request first.
2012-01-20 15:28:54 +01:00
static void abortLocalSync(int sigterm)
{
// logging anything here is not safe (our own logging system might
// have been interrupted by the SIGTERM and thus be in an inconsistent
// state), but let's try it anyway
SE_LOG_INFO(NULL, "local sync child shutting down due to SIGTERM");
local sync: kill syncevo-local-sync with SIGTERM Shutting down syncevo-local-sync in a timely manner when aborting is hard: the process might be stuck in a blocking call which cannot be made to check the abort request (blocking libneon, activesyncd client library, ...). The best that can be done is to let the process be killed by the SIGTERM. To have some trace of that, catch the signal and log the signal; there's a slight risk that the logging system is in an inconsistent state, but overall that risk is minor. Because syncevo-local-sync catches SIGINT, ForkExec::stop() must send SIGTERM in addition to SIGINT. To suppress redundant and misleading ERROR messages when the bad child status is handled, the ForkExecParent remembers that itself asked the child to stop and only treats unexpected "killed by signal" results as error. The local transport must call that stop() in its cancel(). It enters the "canceled" state which prevents all further communication with the child, in particular waiting for the child sync report; doing that would produce another redundant error message about "child exited without sending report". Calling stop() in the local transport's shutdown() is no longer possible, because it would kill the child right away. Before it simply had no effect, because SIGINT was ignored. This points towards an unsolved problem: how long should the parent wait for the child after the sync is done? If the child gets stuck hard after sending its last message, the parent currently waits forever until the user aborts. In the sync event loop the caller of the transport must recognize CANCELED as something which might be desired and thus should not be logged as ERROR. That way the Synthesis engine is called one more time with STEPCMD_ABORT also in those cases where the transport itself detected the abort request first.
2012-01-20 15:28:54 +01:00
// raise the signal again after disabling the handler, to ensure that
// the exit status is "killed by signal xxx" - good because then
// the whoever killed used gets the information that we didn't die for
// some other reason
signal(sigterm, SIG_DFL);
raise(sigterm);
}
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
/**
* Provides the "LogOutput" signal.
* LocalTransportAgentChild adds the method implementations
* before activating it.
*/
class LocalTransportChildImpl : public GDBusCXX::DBusObjectHelper
{
public:
LocalTransportChildImpl(const GDBusCXX::DBusConnectionPtr &conn) :
GDBusCXX::DBusObjectHelper(conn,
LocalTransportChild::path(),
LocalTransportChild::interface(),
GDBusCXX::DBusObjectHelper::Callback_t(),
true),
m_logOutput(*this, LocalTransportChild::logOutputName())
{
add(m_logOutput);
};
GDBusCXX::EmitSignal2<std::string,
std::string,
true /* ignore transmission failures */> m_logOutput;
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
};
Logging: thread-safe Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
2013-04-09 21:32:35 +02:00
class ChildLogger : public Logger
{
std::auto_ptr<LogRedirect> m_parentLogger;
boost::weak_ptr<LocalTransportChildImpl> m_child;
public:
ChildLogger(const boost::shared_ptr<LocalTransportChildImpl> &child) :
m_parentLogger(new LogRedirect(LogRedirect::STDERR_AND_STDOUT)),
m_child(child)
{}
~ChildLogger()
{
m_parentLogger.reset();
}
/**
* Write message into our own log and send to parent.
*/
virtual void messagev(const MessageOptions &options,
const char *format,
va_list args)
{
if (options.m_level <= m_parentLogger->getLevel()) {
m_parentLogger->process();
boost::shared_ptr<LocalTransportChildImpl> child = m_child.lock();
if (child) {
// prefix is used to set session path
// for general server output, the object path field is dbus server
// the object path can't be empty for object paths prevent using empty string.
string strLevel = Logger::levelToStr(options.m_level);
string log = StringPrintfV(format, args);
child->m_logOutput(strLevel, log);
}
Logging: thread-safe Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
2013-04-09 21:32:35 +02:00
}
}
};
class LocalTransportAgentChild : public TransportAgent
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
{
/** final return code of our main(): non-zero indicates that we need to shut down */
int m_ret;
/**
* sync report for client side of the local sync
*/
SyncReport m_clientReport;
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
/** used to capture libneon output */
boost::scoped_ptr<LogRedirect> m_parentLogger;
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* provides connection to parent, created in constructor
*/
boost::shared_ptr<ForkExecChild> m_forkexec;
/**
* proxy for the parent's D-Bus API in onConnect()
*/
boost::shared_ptr<LocalTransportParent> m_parent;
/**
* our D-Bus interface, created in onConnect()
*/
Logging: thread-safe Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
2013-04-09 21:32:35 +02:00
boost::shared_ptr<LocalTransportChildImpl> m_child;
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* sync context, created in Sync() D-Bus call
*/
boost::scoped_ptr<SyncContext> m_client;
/**
* use this D-Bus result handle to send a message from child to parent
* in response to sync() or (later) sendMsg()
*/
LocalTransportChild::ReplyPtr m_msgToParent;
void setMsgToParent(const LocalTransportChild::ReplyPtr &reply,
const std::string &reason)
{
if (m_msgToParent) {
m_msgToParent->failed(GDBusCXX::dbus_error("org.syncevolution.localtransport.error",
"cancelling message: " + reason));
}
m_msgToParent = reply;
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/** content type for message to parent */
std::string m_contentType;
/**
* message from parent
*/
std::string m_message;
/**
* content type of message from parent
*/
std::string m_messageType;
/**
* true after parent has received sync report, or sending failed
*/
bool m_reportSent;
/**
* INACTIVE when idle,
* ACTIVE after having sent and while waiting for next message,
* GOT_REPLY when we have a message to be processed,
* FAILED when permanently broken
*/
Status m_status;
/**
* one loop run + error checking
*/
void step(const std::string &status)
{
SE_LOG_DEBUG(NULL, "local transport: %s", status.c_str());
if (!m_forkexec ||
m_forkexec->getState() == ForkExecChild::DISCONNECTED) {
SE_THROW("local transport child no longer has a parent, terminating");
}
g_main_context_iteration(NULL, true);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_ret) {
SE_THROW("local transport child encountered a problem, terminating");
}
}
static void onParentQuit()
{
// Never free this state blocker. We can only abort and
// quit from now on.
static boost::shared_ptr<SuspendFlags::StateBlocker> abortGuard;
SE_LOG_ERROR(NULL, "sync parent quit unexpectedly");
abortGuard = SuspendFlags::getSuspendFlags().abort();
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void onConnect(const GDBusCXX::DBusConnectionPtr &conn)
{
SE_LOG_DEBUG(NULL, "child connected to parent");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// provide our own API
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
m_child.reset(new LocalTransportChildImpl(conn));
m_child->add(this, &LocalTransportAgentChild::setFreezeLocalSync, LocalTransportChild::setFreezeName());
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_child->add(this, &LocalTransportAgentChild::startSync, LocalTransportChild::startSyncName());
m_child->add(this, &LocalTransportAgentChild::sendMsg, LocalTransportChild::sendMsgName());
m_child->activate();
// set up connection to parent
m_parent.reset(new LocalTransportParent(conn));
}
void onFailure(SyncMLStatus status, const std::string &reason)
{
SE_LOG_DEBUG(NULL, "child fork/exec failed: %s", reason.c_str());
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// record failure for parent
if (!m_clientReport.getStatus()) {
m_clientReport.setStatus(status);
}
if (!reason.empty() &&
m_clientReport.getError().empty()) {
m_clientReport.setError(reason);
}
// return to step()
m_ret = 1;
}
// D-Bus API, see LocalTransportChild;
// must keep number of parameters < 9, the maximum supported by
// our D-Bus binding
void startSync(const std::string &clientConfig,
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
const StringPair &serverConfig, // config name + root path
const std::string &serverLogDir,
bool serverDoLogging,
const std::pair<UserIdentity, InitStateString> &serverSyncCredentials,
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
const FullProps &serverConfigProps,
const LocalTransportChild::ActiveSources_t &sources,
const LocalTransportChild::ReplyPtr &reply)
{
setMsgToParent(reply, "sync() was called");
string peer, context, normalConfig;
normalConfig = SyncConfig::normalizeConfigString(clientConfig);
SyncConfig::splitConfigString(normalConfig, peer, context);
if (peer.empty()) {
peer = "target-config";
}
// Keep the process name short in debug output if it is the
// normal "target-config", be more verbose if it is something
// else because it may be relevant.
if (peer != "target-config") {
Logger::setProcessName(peer + "@" + context);
} else {
Logger::setProcessName("@" + context);
}
SE_LOG_DEBUG(NULL, "Sync() called, starting the sync");
const char *delay = getenv("SYNCEVOLUTION_LOCAL_CHILD_DELAY2");
if (delay) {
Sleep(atoi(delay));
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// initialize sync context
m_client.reset(new SyncContext(peer + "@" + context,
serverConfig.first,
serverConfig.second == "ephemeral" ?
serverConfig.second :
serverConfig.second + "/." + normalConfig,
boost::shared_ptr<TransportAgent>(this, NoopAgentDestructor()),
serverDoLogging));
if (serverConfig.second == "ephemeral") {
m_client->makeEphemeral();
}
boost::shared_ptr<UserInterface> ui(new LocalTransportUI(m_parent));
m_client->setUserInterface(ui);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// allow proceeding with sync even if no "target-config" was created,
// because information about username/password (for WebDAV) or the
// sources (for file backends) might be enough
m_client->setConfigNeeded(false);
// apply temporary config filters
m_client->setConfigFilter(true, "", serverConfigProps.createSyncFilter(m_client->getConfigName()));
BOOST_FOREACH(const string &sourceName, m_client->getSyncSources()) {
m_client->setConfigFilter(false, sourceName, serverConfigProps.createSourceFilter(m_client->getConfigName(), sourceName));
}
// Copy non-empty credentials from main config, because
// that is where the GUI knows how to store them. A better
// solution would be to require that credentials are in the
// "target-config" config.
//
// Interactive password requests later in SyncContext::sync()
// will end up in our LocalTransportContext::askPassword()
// implementation above, which will pass the question to
// the local sync parent.
if (!serverSyncCredentials.first.toString().empty()) {
m_client->setSyncUsername(serverSyncCredentials.first.toString(), true);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
if (!serverSyncCredentials.second.empty()) {
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_client->setSyncPassword(serverSyncCredentials.second, true);
}
// debugging mode: write logs inside sub-directory of parent,
// otherwise use normal log settings
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (!serverDoLogging) {
m_client->setLogDir(std::string(serverLogDir) + "/child", true);
}
// disable all sources temporarily, will be enabled by next loop
BOOST_FOREACH(const string &targetName, m_client->getSyncSources()) {
SyncSourceNodes targetNodes = m_client->getSyncSourceNodes(targetName);
SyncSourceConfig targetSource(targetName, targetNodes);
targetSource.setSync("disabled", true);
}
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
// activate all sources in client targeted by main config,
// with right uri
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
BOOST_FOREACH(const LocalTransportChild::ActiveSources_t::value_type &entry, sources) {
// mapping is from server (source) to child (target)
const std::string &sourceName = entry.first;
const std::string &targetName = entry.second.first;
std::string sync = entry.second.second;
SyncMode mode = StringToSyncMode(sync);
if (mode != SYNC_NONE) {
SyncSourceNodes targetNodes = m_client->getSyncSourceNodes(targetName);
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
SyncSourceConfig targetSource(targetName, targetNodes);
string fullTargetName = normalConfig + "/" + targetName;
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
if (!targetNodes.dataConfigExists()) {
if (targetName.empty()) {
source -> datastore rename, improved terminology The word "source" implies reading, while in fact access is read/write. "datastore" avoids that misconception. Writing it in one word emphasizes that it is single entity. While renaming, also remove references to explicit --*-property parameters. The only necessary use today is "--sync-property ?" and "--datastore-property ?". --datastore-property was used instead of the short --store-property because "store" might be mistaken for the verb. It doesn't matter that it is longer because it doesn't get typed often. --source-property must remain valid for backward compatility. As many user-visible instances of "source" as possible got replaced in text strings by the newer term "datastore". Debug messages were left unchanged unless some regex happened to match it. The source code will continue to use the old variable and class names based on "source". Various documentation enhancements: Better explain what local sync is and how it involves two sync configs. "originating config" gets introduces instead of just "sync config". Better explain the relationship between contexts, sync configs, and source configs ("a sync config can use the datastore configs in the same context"). An entire section on config properties in the terminology section. "item" added (Todd Wilson correctly pointed out that it was missing). Less focus on conflict resolution, as suggested by Graham Cobb. Fix examples that became invalid when fixing the password storage/lookup mechanism for GNOME keyring in 1.4. The "command line conventions", "Synchronization beyond SyncML" and "CalDAV and CardDAV" sections were updated. It's possible that the other sections also contain slightly incorrect usage of the terminology or are simply out-dated.
2014-07-28 15:29:41 +02:00
Exception::throwError(SE_HERE, "missing URI for one of the datastores");
} else {
source -> datastore rename, improved terminology The word "source" implies reading, while in fact access is read/write. "datastore" avoids that misconception. Writing it in one word emphasizes that it is single entity. While renaming, also remove references to explicit --*-property parameters. The only necessary use today is "--sync-property ?" and "--datastore-property ?". --datastore-property was used instead of the short --store-property because "store" might be mistaken for the verb. It doesn't matter that it is longer because it doesn't get typed often. --source-property must remain valid for backward compatility. As many user-visible instances of "source" as possible got replaced in text strings by the newer term "datastore". Debug messages were left unchanged unless some regex happened to match it. The source code will continue to use the old variable and class names based on "source". Various documentation enhancements: Better explain what local sync is and how it involves two sync configs. "originating config" gets introduces instead of just "sync config". Better explain the relationship between contexts, sync configs, and source configs ("a sync config can use the datastore configs in the same context"). An entire section on config properties in the terminology section. "item" added (Todd Wilson correctly pointed out that it was missing). Less focus on conflict resolution, as suggested by Graham Cobb. Fix examples that became invalid when fixing the password storage/lookup mechanism for GNOME keyring in 1.4. The "command line conventions", "Synchronization beyond SyncML" and "CalDAV and CardDAV" sections were updated. It's possible that the other sections also contain slightly incorrect usage of the terminology or are simply out-dated.
2014-07-28 15:29:41 +02:00
Exception::throwError(SE_HERE, StringPrintf("%s: datastore not configured",
fullTargetName.c_str()));
}
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
// All of the config setting is done as volatile,
// so none of the regular config nodes have to
// be written. If a sync mode was set, it must have been
// done before in this loop => error in original config.
if (!targetSource.isDisabled()) {
Exception::throwError(SE_HERE,
source -> datastore rename, improved terminology The word "source" implies reading, while in fact access is read/write. "datastore" avoids that misconception. Writing it in one word emphasizes that it is single entity. While renaming, also remove references to explicit --*-property parameters. The only necessary use today is "--sync-property ?" and "--datastore-property ?". --datastore-property was used instead of the short --store-property because "store" might be mistaken for the verb. It doesn't matter that it is longer because it doesn't get typed often. --source-property must remain valid for backward compatility. As many user-visible instances of "source" as possible got replaced in text strings by the newer term "datastore". Debug messages were left unchanged unless some regex happened to match it. The source code will continue to use the old variable and class names based on "source". Various documentation enhancements: Better explain what local sync is and how it involves two sync configs. "originating config" gets introduces instead of just "sync config". Better explain the relationship between contexts, sync configs, and source configs ("a sync config can use the datastore configs in the same context"). An entire section on config properties in the terminology section. "item" added (Todd Wilson correctly pointed out that it was missing). Less focus on conflict resolution, as suggested by Graham Cobb. Fix examples that became invalid when fixing the password storage/lookup mechanism for GNOME keyring in 1.4. The "command line conventions", "Synchronization beyond SyncML" and "CalDAV and CardDAV" sections were updated. It's possible that the other sections also contain slightly incorrect usage of the terminology or are simply out-dated.
2014-07-28 15:29:41 +02:00
StringPrintf("%s: datastore targetted twice by %s",
fullTargetName.c_str(),
serverConfig.first.c_str()));
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
// invert data direction
if (mode == SYNC_REFRESH_FROM_LOCAL) {
mode = SYNC_REFRESH_FROM_REMOTE;
} else if (mode == SYNC_REFRESH_FROM_REMOTE) {
mode = SYNC_REFRESH_FROM_LOCAL;
} else if (mode == SYNC_ONE_WAY_FROM_LOCAL) {
mode = SYNC_ONE_WAY_FROM_REMOTE;
} else if (mode == SYNC_ONE_WAY_FROM_REMOTE) {
mode = SYNC_ONE_WAY_FROM_LOCAL;
engine: local cache sync mode This patch introduces support for true one-way syncing ("caching"): the local datastore is meant to be an exact copy of the data on the remote side. The assumption is that no modifications are ever made locally outside of syncing. This is different from one-way sync modes, which allows local changes and only temporarily disables sending them to the remote side. Another goal of the new mode is to avoid data writes as much as possible. This new mode only works on the server side of a sync, where the engine has enough control over the data flow. Most of the changes are in libsynthesis. SyncEvolution only needs to enable the new mode, which is done via an extension of the "sync" property: - "local-cache-incremental" will do an incremental sync (if possible) or a slow sync (otherwise). This is usually the right mode to use, and thus has "local-cache" as alias. - "local-cache-slow" will always do a slow sync. Useful for debugging or after (accidentally) making changes on the server side. An incremental sync will ignore such changes because they are not meant to happen and thus leave client and sync out-of-sync! Both modes are recorded in the sync report of the local side. The target side is the client and records the normal "two-way" or "slow" sync modes. With the current SyncEvolution contact field list, first, middle and last name are used to find matches during any kind of slow sync. The organization field is ignored for matching during the initial slow sync and used in all following ones. That's okay, the difference won't matter in practice because the initial slow sync in PBAP caching will be done with no local data. The test achieve the same result in both cases by keeping the organization set in the reduced data set. It's also okay to include the property in the comparison, because it might help to distinguish between "John Doe" in different companies. It might be worthwhile to add more fields as match criteria, for example the birthday. Currently they are excluded, probably because they are not trusted to be supported by SyncML peers. In caching mode the situation is different, because all our data came from the peer. The downside is that in cases where matching has to be done all the time because change detection is not supported (PBAP), including the birthday as criteria will cause unnecessary contact removed/added events (and thus disk IO) when a contact was originally created without birthday locally and then a birthday gets added on the phone. Testing is done as part of the D-Bus testing framework, because usually this functionality will be used as part of the D-Bus server and writing tests in Python is easier. A new test class "TestLocalCache" contains the new tests. They include tests for removing extra items during a slow sync (testItemRemoval), adding new client items under various conditions (testItemAdd*) and updating/removing an item during incremental syncing (testItemUpdate/Delete*). Doing these changes during a slow sync could also be tested (not currently covered). The tests for removing properties (testPropertyRemoval*) cover removing almost all contact properties during an initial slow sync, a second slow sync (which is treated differently in libsynthesis, see merge=always and merge=slowsync), and an incremental sync.
2012-08-23 14:25:55 +02:00
} else if (mode == SYNC_LOCAL_CACHE_SLOW) {
// Remote side is running in caching mode and
// asking for refresh. Send all our data.
mode = SYNC_SLOW;
} else if (mode == SYNC_LOCAL_CACHE_INCREMENTAL) {
// Remote side is running in caching mode and
// asking for an update. Use two-way mode although
// nothing is going to come back (simpler that way
// than using one-way, which has special code
// paths in libsynthesis).
mode = SYNC_TWO_WAY;
}
targetSource.setSync(PrettyPrintSyncMode(mode, true), true);
targetSource.setURI(sourceName, true);
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// ready for m_client->sync()
m_status = ACTIVE;
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void sendMsg(const std::string &contentType,
const GDBusCXX::DBusArray<uint8_t> &data,
const LocalTransportChild::ReplyPtr &reply)
{
SE_LOG_DEBUG(NULL, "child got message of %ld bytes", (long)data.first);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
setMsgToParent(LocalTransportChild::ReplyPtr(), "sendMsg() was called");
if (m_status == ACTIVE) {
m_msgToParent = reply;
m_message.assign(reinterpret_cast<const char *>(data.second),
data.first);
m_messageType = contentType;
m_status = GOT_REPLY;
} else {
reply->failed(GDBusCXX::dbus_error("org.syncevolution.localtransport.error",
"child not expecting any message"));
}
}
// Must not be named setFreeze(), that is a virtual method in
// TransportAgent that we don't want to override!
void setFreezeLocalSync(bool freeze)
{
SE_LOG_DEBUG(NULL, "local transport child: setFreeze(%s)", freeze ? "true" : "false");
if (m_client) {
m_client->setFreeze(freeze);
}
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
public:
LocalTransportAgentChild() :
m_ret(0),
m_forkexec(SyncEvo::ForkExecChild::create()),
m_reportSent(false),
m_status(INACTIVE)
{
m_forkexec->m_onConnect.connect(boost::bind(&LocalTransportAgentChild::onConnect, this, _1));
m_forkexec->m_onFailure.connect(boost::bind(&LocalTransportAgentChild::onFailure, this, _1, _2));
// When parent quits, we need to abort whatever we do and shut
// down. There's no way how we can complete our work without it.
//
// Note that another way how this process can detect the
// death of the parent is when it currently is waiting for
// completion of a method call to the parent, like a request
// for a password. However, that does not cover failures
// like the parent not asking us to sync in the first place
// and also does not work with libdbus (https://bugs.freedesktop.org/show_bug.cgi?id=49728).
m_forkexec->m_onQuit.connect(&onParentQuit);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_forkexec->connect();
}
Logging: thread-safe Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
2013-04-09 21:32:35 +02:00
boost::shared_ptr<ChildLogger> createLogger()
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
{
Logging: thread-safe Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
2013-04-09 21:32:35 +02:00
return boost::shared_ptr<ChildLogger>(new ChildLogger(m_child));
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void run()
{
SuspendFlags &s = SuspendFlags::getSuspendFlags();
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
while (!m_parent) {
if (s.getState() != SuspendFlags::NORMAL) {
SE_LOG_DEBUG(NULL, "aborted, returning while waiting for parent");
return;
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
step("waiting for parent");
}
while (!m_client) {
if (s.getState() != SuspendFlags::NORMAL) {
SE_LOG_DEBUG(NULL, "aborted, returning while waiting for Sync() call from parent");
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
step("waiting for Sync() call from parent");
}
try {
rewrote signal handling Having the signal handling code in SyncContext created an unnecessary dependency of some classes (in particular the transports) on SyncContext.h. Now the code is in its own SuspendFlags.cpp/h files. Cleaning up when the caller is done with signal handling is now part of the utility class (removed automatically when guard instance is freed). The signal handlers now push one byte for each caught signal into a pipe. That byte tells the rest of the code which message it needs to print, which cannot be done in the signal handlers (because the logging code is not reentrant and thus not safe to call from a signal handler). Compared to the previous solution, this solves several problems: - no more race condition between setting and printing the message - the pipe can be watched in a glib event loop, thus removing the need to poll at regular intervals; polling is still possible (and necessary) in those transports which do not integrate with the event loop (CurlTransport) while it can be removed from others (SoupTransport, OBEXTransport) A boost::signal is emitted when the global SuspendFlags change. Automatic connection management is used to disconnect instances which are managed by boost::shared_ptr. For example, the current transport's cancel() method is called when the state changes to "aborted". The early connection phase of the OBEX transport now also can be aborted (required cleaning up that transport!). Currently watching for aborts via the event loop only works for real Unix signals, but not for "abort" flags set in derived SyncContext instances. The plan is to change that by allowing a "set abort" on SuspendFlags and thus making SyncContext::checkForSuspend/checkForAbort() redundant. The new class is used as follows: - syncevolution command line without daemon uses it to control suspend/abort directly - syncevolution command line as client of syncevo-dbus-server connects to the state change signal and relays it to the syncevo-dbus-server session via D-Bus; now all operations are protected like that, not just syncing - syncevo-dbus-server installs its own handlers for SIGINT and SIGTERM and tries to shut down when either of them is received. SuspendFlags then doesn't activate its own handler. Instead that handler is invoked by the syncevo-dbus-server niam() handler, to suspend or abort a running sync. Once syncs run in a separate process, the syncevo-dbus-server should request that these processes suspend or abort before shutting down itself. - The syncevo-local-sync helper ignores SIGINT after a sync has started. It would receive that signal when forked by syncevolution in non-daemon mode and the user presses CTRL-C. Now the signal is only handled in the parent process, which suspends as part of its own side of the SyncML session and aborts by sending a SIGTERM+SIGINT to syncevo-local-sync. SIGTERM in syncevo-local-sync is handled by SuspendFlags and is meant to abort whatever is going on there at the moment (see below). Aborting long-running operations like import/export or communication via CardDAV or ActiveSync still needs further work. The backends need to check the abort state and return early instead of continuing.
2012-01-19 16:11:22 +01:00
// ignore SIGINT signal in local sync helper from now on:
// the parent process will handle those and tell us when
// we are expected to abort by sending a SIGTERM
struct sigaction new_action;
memset(&new_action, 0, sizeof(new_action));
new_action.sa_handler = SIG_IGN;
sigemptyset(&new_action.sa_mask);
sigaction(SIGINT, &new_action, NULL);
local sync: kill syncevo-local-sync with SIGTERM Shutting down syncevo-local-sync in a timely manner when aborting is hard: the process might be stuck in a blocking call which cannot be made to check the abort request (blocking libneon, activesyncd client library, ...). The best that can be done is to let the process be killed by the SIGTERM. To have some trace of that, catch the signal and log the signal; there's a slight risk that the logging system is in an inconsistent state, but overall that risk is minor. Because syncevo-local-sync catches SIGINT, ForkExec::stop() must send SIGTERM in addition to SIGINT. To suppress redundant and misleading ERROR messages when the bad child status is handled, the ForkExecParent remembers that itself asked the child to stop and only treats unexpected "killed by signal" results as error. The local transport must call that stop() in its cancel(). It enters the "canceled" state which prevents all further communication with the child, in particular waiting for the child sync report; doing that would produce another redundant error message about "child exited without sending report". Calling stop() in the local transport's shutdown() is no longer possible, because it would kill the child right away. Before it simply had no effect, because SIGINT was ignored. This points towards an unsolved problem: how long should the parent wait for the child after the sync is done? If the child gets stuck hard after sending its last message, the parent currently waits forever until the user aborts. In the sync event loop the caller of the transport must recognize CANCELED as something which might be desired and thus should not be logged as ERROR. That way the Synthesis engine is called one more time with STEPCMD_ABORT also in those cases where the transport itself detected the abort request first.
2012-01-20 15:28:54 +01:00
// SIGTERM would be caught by SuspendFlags and set the "abort"
// state. But a lot of code running in this process cannot
// check that flag in a timely manner (blocking calls in
// libneon, activesync client libraries, ...). Therefore
// it is better to abort inside the signal handler.
new_action.sa_handler = abortLocalSync;
sigaction(SIGTERM, &new_action, NULL);
SE_LOG_DEBUG(NULL, "LocalTransportChild: ignore SIGINT, die in SIGTERM");
SE_LOG_INFO(NULL, "target side of local sync ready");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_client->sync(&m_clientReport);
} catch (...) {
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
string explanation;
SyncMLStatus status = Exception::handle(explanation);
m_clientReport.setStatus(status);
if (!explanation.empty() &&
m_clientReport.getError().empty()) {
m_clientReport.setError(explanation);
}
if (m_parent) {
std::string report = m_clientReport.toString();
SE_LOG_DEBUG(NULL, "child sending sync report after failure:\n%s", report.c_str());
m_parent->m_storeSyncReport.start(report,
boost::bind(&LocalTransportAgentChild::syncReportReceived, this, _1));
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// wait for acknowledgement for report once:
// we are in some kind of error state, better
// do not wait too long
if (m_parent) {
SE_LOG_DEBUG(NULL, "waiting for parent's ACK for sync report");
g_main_context_iteration(NULL, true);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
}
throw;
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_parent) {
// send final report, ignore result
std::string report = m_clientReport.toString();
SE_LOG_DEBUG(NULL, "child sending sync report:\n%s", report.c_str());
m_parent->m_storeSyncReport.start(report,
boost::bind(&LocalTransportAgentChild::syncReportReceived, this, _1));
while (!m_reportSent && m_parent &&
s.getState() == SuspendFlags::NORMAL) {
step("waiting for parent's ACK for sync report");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
}
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
void syncReportReceived(const std::string &error)
{
SE_LOG_DEBUG(NULL, "sending sync report to parent: %s",
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
error.empty() ? "done" : error.c_str());
m_reportSent = true;
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
int getReturnCode() const { return m_ret; }
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* set transport specific URL of next message
*/
virtual void setURL(const std::string &url) {}
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* define content type for post, see content type constants
*/
virtual void setContentType(const std::string &type)
{
m_contentType = type;
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* Requests an normal shutdown of the transport. This can take a
* while, for example if communication is still pending.
* Therefore wait() has to be called to ensure that the
* shutdown is complete and that no error occurred.
*
* Simply deleting the transport is an *unnormal* shutdown that
* does not communicate with the peer.
*/
virtual void shutdown()
{
SE_LOG_DEBUG(NULL, "child local transport shutting down");
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_msgToParent) {
// Must send non-zero message, empty messages cause an
// error during D-Bus message decoding on the receiving
// side. Content doesn't matter, ignored by parent.
m_msgToParent->done("shutdown-message", GDBusCXX::makeDBusArray(1, (uint8_t *)""));
m_msgToParent.reset();
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_status != FAILED) {
m_status = CLOSED;
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* start sending message
*
* Memory must remain valid until reply is received or
* message transmission is canceled.
*
* @param data start address of data to send
* @param len number of bytes
*/
virtual void send(const char *data, size_t len)
{
SE_LOG_DEBUG(NULL, "child local transport sending %ld bytes", (long)len);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_msgToParent) {
m_status = ACTIVE;
m_msgToParent->done(m_contentType, GDBusCXX::makeDBusArray(len, (uint8_t *)(data)));
m_msgToParent.reset();
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
} else {
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
m_status = FAILED;
SE_THROW("cannot send data to parent because parent is not waiting for message");
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* cancel an active message transmission
*
* Blocks until send buffer is no longer in use.
* Returns immediately if nothing pending.
*/
virtual void cancel() {}
/**
* Wait for completion of an operation initiated earlier.
* The operation can be a send with optional reply or
* a close request.
*
* Returns immediately if no operations is pending.
*
* @param noReply true if no reply is required for a running send;
* only relevant for transports used by a SyncML server
*/
virtual Status wait(bool noReply = false)
{
SuspendFlags &s = SuspendFlags::getSuspendFlags();
while (m_status == ACTIVE &&
s.getState() == SuspendFlags::NORMAL) {
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
step("waiting for next message");
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
return m_status;
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
/**
* Tells the transport agent to stop the transmission the given
* amount of seconds after send() was called. The transport agent
* will then stop the message transmission and return a TIME_OUT
* status in wait().
*
* @param seconds number of seconds to wait before timing out, zero for no timeout
*/
virtual void setTimeout(int seconds) {}
/**
* provides access to reply data
*
* Memory pointer remains valid as long as
* transport agent is not deleted and no other
* message is sent.
*/
virtual void getReply(const char *&data, size_t &len, std::string &contentType)
{
SE_LOG_DEBUG(NULL, "processing %ld bytes in child", (long)m_message.size());
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
if (m_status != GOT_REPLY) {
SE_THROW("getReply() called in child when no reply available");
}
data = m_message.c_str();
len = m_message.size();
contentType = m_messageType;
}
};
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
int LocalTransportMain(int argc, char **argv)
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
{
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
// delay the client for debugging purposes
const char *delay = getenv("SYNCEVOLUTION_LOCAL_CHILD_DELAY");
if (delay) {
Sleep(atoi(delay));
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
SyncContext::initMain("syncevo-local-sync");
// Our stderr is either connected to the original stderr (when
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
// SYNCEVOLUTION_DEBUG is set) or the local sync's parent
// LogRedirect. However, that stderr is not normally used.
// Instead we install our own LogRedirect for both stdout (for
// Execute() and synccompare, which then knows that it needs to
// capture the output) and stderr (to get output like the one from
// libneon into the child log) in LocalTransportAgentChild and
// send all logging output to the local sync parent via D-Bus, to
// be forwarded to the user as part of the normal message stream
// of the sync session.
local sync: improved target side output Added a "target side of local sync ready" INFO message to introduce the output which has the target context in the [INFO] tag. The sync report from the target side now has the target context embedded in brackets after the "Changes applied during synchronization" header, to avoid ambiguities. Output from the target side of a local sync was passed through stderr redirection as chunks of text to the frontends. This had several drawbacks: - forwarding only happened when the local sync parent was processing the output redirection, which (due to limitations of the implementation) only happens when it needs to print something itself - debug messages were not forwarded - message boundaries might have been lost In particular INFO messages about delays on the target side are relevant while the sync runs and need to be shown immediately. Now the output is passed through D-Bus, which happens immediately, preserves message boundaries and is done for all output. The frontend can decide separately whether it shows debug messages (not currently supported by the command line tool). Implementing this required extending the D-Bus API. The Server.LogOutput signal now has an additional "process name" parameter. Normally it is empty. For messages originating from the target side, it carries that extra target context string. This D-Bus API change is backward compatible. Older clients can still subscribe to and decode the LogOutput messages, they'll simply ignore the extra parameter. Newer clients expecting that extra parameter won't work with an older D-Bus daemon: they'll fail to decode the D-Bus message. This revealed that the last error messages in a session was incorrectly attributed to the syncevo-dbus-server. Might also have happened with several other error messages. Now everything happening in the server while working on code related to a session is logged as coming from that sessions. It's not perfect either (some of the output could be from unrelated events encountered indirectly while running that code), but it should be better than before. The patch changes the handling or errors in the local sync parent slightly: because it logs real ERROR messages now instead of plain text, it'll record the child's errors in its own sync report. That's okay, user's typically shouldn't have to care about where the error occurred. The D-Bus tests need to be adapted for this, because it removes the "failure in local sync child" from the sync report. Another, more internal change is that the syncevo-local-sync helper does its own output redirection instead of relying on the stderr handling of the parent. That way libneon debug output ends up in the log file of the child side (where it belongs) and not in the parent's log.
2012-06-28 14:58:05 +02:00
setvbuf(stderr, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
// SIGPIPE must be ignored, some system libs (glib GIO?) trigger
// it. SIGINT/TERM will be handled via SuspendFlags once the sync
// runs.
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
try {
if (getenv("SYNCEVOLUTION_DEBUG")) {
Logger::instance().setLevel(Logger::DEBUG);
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
}
// process name will be set to target config name once it is known
Logger::setProcessName("syncevo-local-sync");
boost::shared_ptr<LocalTransportAgentChild> child(new LocalTransportAgentChild);
Logging: thread-safe Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
2013-04-09 21:32:35 +02:00
PushLogger<Logger> logger;
// Temporary handle is necessary to avoid compiler issue with
// clang (ambiguous brackets).
{
Logger::Handle handle(child->createLogger());
logger.reset(handle);
}
#ifdef USE_DLT
// Set by syncevo-dbus-server for us.
bool useDLT = getenv("SYNCEVOLUTION_USE_DLT") != NULL;
PushLogger<LoggerDLT> loggerdlt;
if (useDLT) {
loggerdlt.reset(new LoggerDLT(DLT_SYNCEVO_LOCAL_HELPER_ID, "SyncEvolution local sync helper"));
}
#endif
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
child->run();
int ret = child->getReturnCode();
Logging: thread-safe Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
2013-04-09 21:32:35 +02:00
logger.reset();
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
child.reset();
return ret;
} catch ( const std::exception &ex ) {
SE_LOG_ERROR(NULL, "%s", ex.what());
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
} catch (...) {
SE_LOG_ERROR(NULL, "unknown error");
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
local sync: execute 'syncevo-local-sync' on child side, communicate via D-Bus Instead of forking and continuing to sync in the forked process without an explicit exec(), exec() the 'syncevo-local-sync' helper in the forked process. The syncevo-local-sync helper binary gets installed into libexec. SYNCEVOLUTION_LIBEXEC_DIR must be set if that helper is not installed yet, not in the PATH, or an old version would be found without that env variable ("make" without "make install" during development!). Main advantage is the cleaner environment for running the child side of local sync. Required for getting ActiveSync to work again (GDBus GIO as used by recent activesyncd client libraries did not work in the forked process without the exec()). Full D-Bus communication gets established between parent and child. The downside is the hard dependency of local sync on the D-Bus libraries (not the daemon!). D-Bus communication allowed implementing interactive password requests from the child side through the parent to the UI using the parent, something that wasn't implemented before. The child asks its parent for the password, which in turn passes the request to its SyncContext. This happens to work when that SyncContext is a normal instance (reads from stdin, the "syncevolution --daemon" case) and the syncevo-dbus-server (sends out an Info Request signal and waits for a response). The info request and response are handled in the blocking askPassword() by polling the running mail loop, so the parent should remain responsive. Overall it is still a pretty difficult setup; it would be better if askPassword() was asynchronous. Describing the required password also is sub-optimal: the sync-ui just asks for a password in its current config (even though that might not be the config which currently gets synced) and crashes if no config is currently selected. The command line uses the description derived from the property and config name, which is a bit technical, but at least correct. Syncing uses the child's error string as "first error" in the parent, too, by logging it anew on the parent side. That puts it into the parent's sync report ahead of any additional error that it might encounter while the child shuts down. Also use the child's status when available instead of a misleading TransportError. In addition, suppress as many of these errors as possible when we know already that the child reported an error in its sync report. Not all "transport errors" are currently avoided that way, but this is at least a first step.
2012-01-09 16:30:53 +01:00
return 1;
support local sync (BMC #712) Local sync is configured with a new syncURL = local://<context> where <context> identifies the set of databases to synchronize with. The URI of each source in the config identifies the source in that context to synchronize with. The databases in that context run a SyncML session as client. The config itself is for a server. Reversing these roles is possible by putting the config into the other context. A sync is started by the server side, via the new LocalTransportAgent. That agent forks, sets up the client side, then passes messages back and forth via stream sockets. Stream sockets are useful because unexpected peer shutdown can be detected. Running the server side requires a few changes: - do not send a SAN message, the client will start the message exchange based on the config - wait for that message before doing anything The client side is more difficult: - Per-peer config nodes do not exist in the target context. They are stored in a hidden .<context> directory inside the server config tree. This depends on the new "registering nodes in the tree" feature. All nodes are hidden, because users are not meant to edit any of them. Their name is intentionally chosen like traditional nodes so that removing the config also removes the new files. - All relevant per-peer properties must be copied from the server config (log level, printing changes, ...); they cannot be set differently. Because two separate SyncML sessions are used, we end up with two normal session directories and log files. The implementation is not complete yet: - no glib support, so cannot be used in syncevo-dbus-server - no support for CTRL-C and abort - no interactive password entry for target sources - unexpected slow syncs are detected on the client side, but not reported properly on the server side
2010-07-31 18:28:53 +02:00
}
SE_END_CXX