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 <stddef.h>
|
2010-10-20 14:14:28 +02:00
|
|
|
#include <sys/socket.h>
|
2010-10-29 11:20:11 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.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 <syncevo/declarations.h>
|
|
|
|
SE_BEGIN_CXX
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SyncML message data. Header followed directly by data.
|
|
|
|
*/
|
|
|
|
struct SyncMLMessage
|
|
|
|
{
|
|
|
|
Message m_message;
|
|
|
|
char m_data[0];
|
|
|
|
};
|
|
|
|
|
|
|
|
class NoopAgentDestructor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void operator () (TransportAgent *agent) throw() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
LocalTransportAgent::LocalTransportAgent(SyncContext *server,
|
|
|
|
const std::string &clientContext,
|
|
|
|
void *loop) :
|
|
|
|
m_server(server),
|
2010-08-02 13:22:01 +02:00
|
|
|
m_clientContext(SyncConfig::normalizeConfigString(clientContext)),
|
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_loop(static_cast<GMainLoop *>(loop)),
|
|
|
|
m_status(INACTIVE),
|
|
|
|
m_receiveBufferSize(0),
|
2010-10-29 11:20:11 +02:00
|
|
|
m_receivedBytes(0),
|
|
|
|
m_pid(0)
|
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()
|
|
|
|
{
|
2010-10-29 11:20:11 +02:00
|
|
|
if (m_pid) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "starting to wait for child process %ld in destructor", (long)m_pid);
|
|
|
|
int status;
|
|
|
|
pid_t res = waitpid(m_pid, &status, 0);
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "child %ld completed, status %d", (long)res, 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
|
|
|
}
|
|
|
|
|
|
|
|
void LocalTransportAgent::start()
|
|
|
|
{
|
|
|
|
int sockets[2];
|
|
|
|
|
2010-08-02 13:22:01 +02:00
|
|
|
// compare normalized context names to detect forbidden sync
|
|
|
|
// within the same context; they could be set up, but are more
|
|
|
|
// likely configuration mistakes
|
|
|
|
string peer, context;
|
|
|
|
SyncConfig::splitConfigString(m_clientContext, peer, context);
|
|
|
|
if (!peer.empty()) {
|
|
|
|
SE_THROW(StringPrintf("invalid local sync URL: '%s' references a peer config, should point to a context like @%s instead",
|
|
|
|
m_clientContext.c_str(),
|
|
|
|
context.c_str()));
|
|
|
|
}
|
2010-10-25 10:41:17 +02:00
|
|
|
if (m_clientContext == m_server->getContextName()) {
|
2010-08-02 13:22:01 +02:00
|
|
|
SE_THROW(StringPrintf("invalid local sync inside context '%s', need second context with different databases", context.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
|
|
|
if (socketpair(AF_LOCAL,
|
|
|
|
SOCK_STREAM,
|
|
|
|
0, sockets)) {
|
|
|
|
m_server->throwError("socketpair()", errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t pid = fork();
|
|
|
|
switch (pid) {
|
|
|
|
case -1:
|
|
|
|
m_server->throwError("fork()", errno);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
// child
|
|
|
|
close(sockets[0]);
|
|
|
|
m_messageFD = sockets[1];
|
|
|
|
run();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// parent
|
|
|
|
close(sockets[1]);
|
|
|
|
m_messageFD = sockets[0];
|
|
|
|
// first message must come from child
|
|
|
|
m_status = ACTIVE;
|
2010-10-29 11:20:11 +02:00
|
|
|
m_pid = pid;
|
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
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalTransportAgent::run()
|
|
|
|
{
|
|
|
|
// If we did an exec here, we could start with a clean slate.
|
|
|
|
// But that forces us to pass all relevant parameters to some
|
|
|
|
// specific executable, which is more complicated than simply
|
|
|
|
// reading from the existing in-process variables. So let's
|
|
|
|
// try without exec, after some clean up.
|
|
|
|
|
|
|
|
// Remove writing into the parent's log file => implemented as
|
|
|
|
// removing every logger until we run into the parents LogRedirect
|
|
|
|
// instance. That instance needs to be remembered and flushed
|
|
|
|
// before this process may terminate.
|
|
|
|
int index = LoggerBase::numLoggers();
|
|
|
|
LogRedirect *redirect = NULL;
|
|
|
|
--index;
|
|
|
|
while (index >= 0 &&
|
|
|
|
!(redirect = dynamic_cast<LogRedirect *>(LoggerBase::loggerAt(index)))) {
|
|
|
|
LoggerBase::popLogger();
|
|
|
|
--index;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now run. Under no circumstances must we leave this function,
|
|
|
|
// because our caller is not prepared for running inside a forked
|
|
|
|
// process.
|
|
|
|
int res = 0;
|
|
|
|
try {
|
2010-10-22 14:02:01 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "client is running");
|
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
|
|
|
// TODO: password and abort handling in a derived class
|
2010-10-22 11:41:50 +02:00
|
|
|
SyncContext client(std::string("source-config") + m_clientContext,
|
local sync: avoid confusion about what data is changed
In local sync the terms "local" and "remote" (in SyncReport, "Data
modified locally") do not always apply and can be confusing. Replaced
with explicitly mentioning the context.
The source name also no longer is unique. Extended in the local sync
case (and only in that case) by adding a <context>/ prefix to the
source name.
Here is an example of the modified output:
$ syncevolution google
[INFO] @default/itodo20: inactive
[INFO] @default/addressbook: inactive
[INFO] @default/calendar+todo: inactive
[INFO] @default/memo: inactive
[INFO] @default/ical20: inactive
[INFO] @default/todo: inactive
[INFO] @default/file_calendar+todo: inactive
[INFO] @default/file_vcard21: inactive
[INFO] @default/vcard30: inactive
[INFO] @default/text: inactive
[INFO] @default/file_itodo20: inactive
[INFO] @default/vcard21: inactive
[INFO] @default/file_ical20: inactive
[INFO] @default/file_vcard30: inactive
[INFO] @google/addressbook: inactive
[INFO] @google/memo: inactive
[INFO] @google/todo: inactive
[INFO] @google/calendar: starting normal sync, two-way
Local data changes to be applied remotely during synchronization:
*** @google/calendar ***
after last sync | current data
removed since last sync <
> added since last sync
-------------------------------------------------------------------------------
BEGIN:VCALENDAR BEGIN:VCALENDAR
...
END:VCALENDAR END:VCALENDAR
-------------------------------------------------------------------------------
[INFO] @google/calendar: sent 1/2
[INFO] @google/calendar: sent 2/2
Local data changes to be applied remotely during synchronization:
*** @default/calendar ***
no changes
[INFO] @default/calendar: started
[INFO] @default/calendar: updating "created in Google, online"
[INFO] @default/calendar: updating "created in Google - mod2, online"
[INFO] @google/calendar: started
[INFO] @default/calendar: inactive
[INFO] @google/calendar: normal sync done successfully
Synchronization successful.
Changes applied during synchronization:
+---------------|-----------------------|-----------------------|-CON-+
| | @default | @google | FLI |
| Source | NEW | MOD | DEL | ERR | NEW | MOD | DEL | ERR | CTS |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| calendar | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| disabled, 0 KB sent by client, 2 KB received |
| item(s) in database backup: 3 before sync, 3 after it |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| start Mon Oct 25 10:03:24 2010, duration 0:13min |
| synchronization completed successfully |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Data modified @default during synchronization:
*** @default/calendar ***
before sync | after sync
removed during sync <
> added during sync
-------------------------------------------------------------------------------
BEGIN:VCALENDAR BEGIN:VCALENDAR
VERSION:2.0 VERSION:2.0
...
END:VCALENDAR END:VCALENDAR
-------------------------------------------------------------------------------
pohly@pohly-mobl1:/tmp/syncevolution/src$
Synchronization successful.
Changes applied during synchronization:
+---------------|-----------------------|-----------------------|-CON-+
| | @google | @default | FLI |
| Source | NEW | MOD | DEL | ERR | NEW | MOD | DEL | ERR | CTS |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| calendar | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 |
| two-way, 2 KB sent by client, 0 KB received |
| item(s) in database backup: 2 before sync, 2 after it |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| start Mon Oct 25 10:03:24 2010, duration 0:13min |
| synchronization completed successfully |
+---------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+
Data modified @google during synchronization:
*** @google/calendar ***
no changes
2010-10-25 10:34:23 +02:00
|
|
|
m_server->getConfigName(),
|
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_server->getRootPath() + "/." + m_clientContext,
|
|
|
|
boost::shared_ptr<TransportAgent>(this, NoopAgentDestructor()),
|
|
|
|
true);
|
|
|
|
|
2010-10-29 11:17:34 +02:00
|
|
|
// Copy some changes from main config: this is the only way
|
|
|
|
// how they can be set temporarily during a sync.
|
|
|
|
// TODO: find a way to have separate temporary settings
|
|
|
|
// for both sides.
|
|
|
|
client.setLogLevel(m_server->getLogLevel(), true);
|
|
|
|
client.setUsername(m_server->getUsername(), true);
|
|
|
|
client.setPassword(m_server->getPassword(), true);
|
|
|
|
client.setPreventSlowSync(m_server->getPreventSlowSync(), true);
|
|
|
|
client.setPrintChanges(m_server->getPrintChanges(), true);
|
2010-10-29 16:03:39 +02:00
|
|
|
client.setDumpData(m_server->getDumpData(), true);
|
2010-10-29 11:17:34 +02:00
|
|
|
|
2010-10-22 11:41:50 +02:00
|
|
|
// disable all sources temporarily, will be enabled by next loop
|
|
|
|
BOOST_FOREACH(const string &targetName, client.getSyncSources()) {
|
|
|
|
SyncSourceNodes targetNodes = 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
|
|
|
|
BOOST_FOREACH(const string &sourceName, m_server->getSyncSources()) {
|
|
|
|
SyncSourceNodes nodes = m_server->getSyncSourceNodesNoTracking(sourceName);
|
|
|
|
SyncSourceConfig source(sourceName, nodes);
|
|
|
|
string sync = source.getSync();
|
|
|
|
if (sync != "disabled") {
|
|
|
|
string targetName = source.getURI();
|
|
|
|
SyncSourceNodes targetNodes = client.getSyncSourceNodes(targetName);
|
|
|
|
SyncSourceConfig targetSource(targetName, targetNodes);
|
|
|
|
string fullTargetName = m_clientContext + "/" + targetName;
|
|
|
|
|
|
|
|
if (!targetNodes.dataConfigExists()) {
|
|
|
|
client.throwError(StringPrintf("%s: source not configured",
|
|
|
|
fullTargetName.c_str()));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 (string(targetSource.getSync()) != "disabled") {
|
|
|
|
client.throwError(StringPrintf("%s: source targetted twice by %s",
|
|
|
|
fullTargetName.c_str(),
|
|
|
|
m_clientContext.c_str()));
|
|
|
|
}
|
|
|
|
targetSource.setSync(sync.c_str(), true);
|
|
|
|
targetSource.setURI(sourceName.c_str(), true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now sync
|
|
|
|
client.sync(&m_clientReport);
|
|
|
|
} catch(...) {
|
|
|
|
SyncMLStatus status = m_clientReport.getStatus();
|
|
|
|
Exception::handle(&status, redirect);
|
|
|
|
m_clientReport.setStatus(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (redirect) {
|
|
|
|
redirect->flush();
|
|
|
|
}
|
2010-10-29 11:20:11 +02:00
|
|
|
_exit(res);
|
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 LocalTransportAgent::getClientSyncReport(SyncReport &report)
|
|
|
|
{
|
|
|
|
report = m_clientReport;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalTransportAgent::setContentType(const std::string &type)
|
|
|
|
{
|
|
|
|
if (type == m_contentTypeSyncML) {
|
|
|
|
m_sendType = Message::MSG_SYNCML_XML;
|
|
|
|
} else if (type == m_contentTypeSyncWBXML) {
|
|
|
|
m_sendType = Message::MSG_SYNCML_WBXML;
|
|
|
|
} else {
|
|
|
|
SE_THROW(string("unsupported content type: ") + type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalTransportAgent::shutdown()
|
|
|
|
{
|
|
|
|
if (m_pid) {
|
|
|
|
// TODO: get sync report, then wait for exit in child.
|
2010-10-29 11:20:11 +02:00
|
|
|
close(m_messageFD);
|
|
|
|
int status;
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "starting to wait for child process %ld in shutdown()", (long)m_pid);
|
|
|
|
pid_t res = waitpid(m_pid, &status, 0);
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "child %ld completed, status %d", (long)res, status);
|
|
|
|
m_pid = 0;
|
|
|
|
} else {
|
|
|
|
close(m_messageFD);
|
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 LocalTransportAgent::send(const char *data, size_t len)
|
|
|
|
{
|
|
|
|
if (m_loop) {
|
|
|
|
SE_THROW("glib support not implemented");
|
|
|
|
} else {
|
|
|
|
// first throw away old received message
|
|
|
|
if (m_receivedBytes >= sizeof(Message) &&
|
|
|
|
m_receiveBuffer->m_length <= m_receivedBytes) {
|
|
|
|
size_t len = m_receiveBuffer->m_length;
|
|
|
|
// memmove() probably never necessary because receiving
|
|
|
|
// ends directly after complete message, but doesn't hurt
|
|
|
|
// either...
|
|
|
|
memmove(m_receiveBuffer.get(),
|
|
|
|
(char *)m_receiveBuffer.get() + len,
|
|
|
|
m_receivedBytes - len);
|
|
|
|
m_receivedBytes -= len;
|
|
|
|
}
|
|
|
|
|
|
|
|
SyncMLMessage header;
|
|
|
|
header.m_message.m_type = m_sendType;
|
|
|
|
header.m_message.m_length = sizeof(Message) + len;
|
|
|
|
struct iovec vec[2];
|
|
|
|
vec[0].iov_base = &header;
|
|
|
|
vec[0].iov_len = offsetof(SyncMLMessage, m_data);
|
|
|
|
vec[1].iov_base = (void *)data;
|
|
|
|
vec[1].iov_len = len;
|
|
|
|
// TODO: handle timeouts and aborts while writing
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: sending %ld bytes",
|
|
|
|
m_pid ? "parent" : "child",
|
|
|
|
(long)len);
|
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 (writev(m_messageFD, vec, 2) == -1) {
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: sending %ld bytes failed",
|
|
|
|
m_pid ? "parent" : "child",
|
|
|
|
(long)len);
|
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_THROW_EXCEPTION(TransportException,
|
|
|
|
StringPrintf("writev(): %s", strerror(errno)));
|
|
|
|
}
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: sending %ld bytes done",
|
|
|
|
m_pid ? "parent" : "child",
|
|
|
|
(long)len);
|
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 = ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalTransportAgent::cancel()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TransportAgent::Status LocalTransportAgent::wait(bool noReply)
|
|
|
|
{
|
|
|
|
switch (m_status) {
|
|
|
|
case ACTIVE:
|
|
|
|
// need next message; for noReply == true, it is the SyncReport (TODO)
|
|
|
|
if (noReply) {
|
|
|
|
// TODO: remove this code and send SyncReport as last message in client
|
|
|
|
m_status = INACTIVE;
|
|
|
|
return m_status;
|
|
|
|
}
|
|
|
|
if (m_loop) {
|
|
|
|
SE_THROW("glib support not implemented");
|
|
|
|
} else {
|
|
|
|
while (m_status == ACTIVE &&
|
|
|
|
(!m_receiveBufferSize ||
|
|
|
|
m_receiveBufferSize < sizeof(Message) ||
|
|
|
|
m_receivedBytes < m_receiveBuffer->m_length)) {
|
|
|
|
// use select to implement timeout (TODO)
|
|
|
|
fd_set readfds;
|
|
|
|
FD_ZERO(&readfds);
|
|
|
|
FD_SET(m_messageFD, &readfds);
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: waiting",
|
|
|
|
m_pid ? "parent" : "child");
|
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
|
|
|
int res = select(m_messageFD + 1, &readfds, NULL, NULL, NULL);
|
|
|
|
switch (res) {
|
|
|
|
case 0:
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: select timeout",
|
|
|
|
m_pid ? "parent" : "child");
|
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
|
|
|
// TODO: timeout
|
|
|
|
SE_THROW("internal error, unexpected timeout");
|
|
|
|
break;
|
|
|
|
case 1: {
|
|
|
|
// data ready, ensure that buffer is available
|
|
|
|
if (!m_receiveBufferSize) {
|
|
|
|
m_receiveBufferSize = m_server->getMaxMsgSize();
|
|
|
|
m_receiveBuffer.set(static_cast<Message *>(malloc(m_receiveBufferSize)),
|
|
|
|
"Message Buffer");
|
|
|
|
} else if (m_receivedBytes >= sizeof(Message) &&
|
|
|
|
m_receiveBuffer->m_length > m_receiveBufferSize) {
|
|
|
|
m_receiveBuffer.set(static_cast<Message *>(realloc(m_receiveBuffer.release(), m_receiveBuffer->m_length)),
|
|
|
|
"Message Buffer");
|
|
|
|
}
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: recv",
|
|
|
|
m_pid ? "parent" : "child");
|
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
|
|
|
ssize_t recvd = recv(m_messageFD,
|
|
|
|
(char *)m_receiveBuffer.get() + m_receivedBytes,
|
|
|
|
m_receiveBufferSize - m_receivedBytes,
|
|
|
|
MSG_DONTWAIT);
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: received %ld",
|
|
|
|
m_pid ? "parent" : "child",
|
|
|
|
(long)recvd);
|
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 (recvd < 0) {
|
|
|
|
SE_THROW_EXCEPTION(TransportException,
|
|
|
|
StringPrintf("message receive: %s", strerror(errno)));
|
|
|
|
} else if (!recvd) {
|
|
|
|
SE_THROW_EXCEPTION(TransportException,
|
|
|
|
"client has died unexpectedly");
|
|
|
|
}
|
|
|
|
m_receivedBytes += recvd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2010-10-29 11:20:11 +02:00
|
|
|
SE_LOG_DEBUG(NULL, NULL, "%s: select errror: %s",
|
|
|
|
m_pid ? "parent" : "child",
|
|
|
|
strerror(errno));
|
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_THROW_EXCEPTION(TransportException,
|
|
|
|
StringPrintf("select(): %s", strerror(errno)));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_status == ACTIVE) {
|
|
|
|
// complete message received, check if it is SyncML
|
|
|
|
switch (m_receiveBuffer->m_type) {
|
|
|
|
case Message::MSG_SYNCML_XML:
|
|
|
|
case Message::MSG_SYNCML_WBXML:
|
|
|
|
m_status = GOT_REPLY;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// TODO: handle other types
|
|
|
|
SE_THROW("unsupported message type");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return m_status;
|
|
|
|
}
|
|
|
|
return m_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalTransportAgent::getReply(const char *&data, size_t &len, std::string &contentType)
|
|
|
|
{
|
|
|
|
if (m_status != GOT_REPLY) {
|
|
|
|
SE_THROW("internal error, no reply available");
|
|
|
|
}
|
|
|
|
switch (m_receiveBuffer->m_type) {
|
|
|
|
case Message::MSG_SYNCML_XML:
|
|
|
|
contentType = m_contentTypeSyncML;
|
|
|
|
break;
|
|
|
|
case Message::MSG_SYNCML_WBXML:
|
|
|
|
contentType = m_contentTypeSyncWBXML;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
contentType = "";
|
|
|
|
SE_THROW("internal error, no the right message");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!contentType.empty()) {
|
|
|
|
SyncMLMessage *msg = reinterpret_cast<SyncMLMessage *>(m_receiveBuffer.get());
|
|
|
|
len = m_receiveBuffer->m_length - offsetof(SyncMLMessage, m_data);
|
|
|
|
data = msg->m_data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalTransportAgent::setCallback (TransportCallback cb, void * udata, int interval)
|
|
|
|
{
|
|
|
|
// TODO: implement timeout mechanism
|
|
|
|
}
|
|
|
|
|
|
|
|
SE_END_CXX
|