You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
892 lines
30 KiB
892 lines
30 KiB
4 years ago
|
/*
|
||
|
* libosengine - A synchronization engine for the opensync framework
|
||
|
* Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
|
||
|
*
|
||
|
* 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) any later version.
|
||
|
*
|
||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
#include "engine.h"
|
||
|
#include <glib.h>
|
||
|
#include <opensync/opensync_support.h>
|
||
|
#include "opensync/opensync_format_internals.h"
|
||
|
#include "opensync/opensync_member_internals.h"
|
||
|
#include "opensync/opensync_message_internals.h"
|
||
|
#include "opensync/opensync_queue_internals.h"
|
||
|
|
||
|
#include "engine_internals.h"
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <errno.h>
|
||
|
#include <signal.h>
|
||
|
|
||
|
/*! @brief This function can be used to receive GET_ENTRY command replies
|
||
|
*
|
||
|
* See OSyncMessageHandler
|
||
|
*
|
||
|
*/
|
||
|
void _get_changes_reply_receiver(OSyncMessage *message, OSyncClient *sender)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, message, sender);
|
||
|
OSyncEngine *engine = sender->engine;
|
||
|
|
||
|
if (osync_message_is_error(message)) {
|
||
|
OSyncError *error = NULL;
|
||
|
osync_demarshal_error(message, &error);
|
||
|
osync_error_duplicate(&engine->error, &error);
|
||
|
osync_debug("ENG", 1, "Get changes command reply was a error: %s", osync_error_print(&error));
|
||
|
osync_status_update_member(engine, sender, MEMBER_GET_CHANGES_ERROR, &error);
|
||
|
osync_error_update(&engine->error, "Unable to read from one of the members");
|
||
|
osync_flag_unset(sender->fl_sent_changes);
|
||
|
//osync_flag_set(sender->fl_finished);
|
||
|
osync_flag_set(sender->fl_done);
|
||
|
/*
|
||
|
* FIXME: For now we want to stop the engine if
|
||
|
* one of the member didnt connect yet. Later it should
|
||
|
* be that if >= 2 members connect, the sync should continue
|
||
|
*/
|
||
|
osync_flag_set(engine->fl_stop);
|
||
|
|
||
|
} else {
|
||
|
osync_status_update_member(engine, sender, MEMBER_SENT_CHANGES, NULL);
|
||
|
osync_flag_set(sender->fl_sent_changes);
|
||
|
}
|
||
|
|
||
|
osengine_client_decider(engine, sender);
|
||
|
osync_trace(TRACE_EXIT, "_get_changes_reply_receiver");
|
||
|
}
|
||
|
|
||
|
/*! @brief This function can be used to receive CONNECT command replies
|
||
|
*
|
||
|
* See OSyncMessageHandler
|
||
|
*
|
||
|
*/
|
||
|
void _connect_reply_receiver(OSyncMessage *message, OSyncClient *sender)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "_connect_reply_receiver(%p, %p)", message, sender);
|
||
|
|
||
|
osync_trace(TRACE_INTERNAL, "connect reply %i", osync_message_is_error(message));
|
||
|
OSyncEngine *engine = sender->engine;
|
||
|
|
||
|
if (osync_message_is_error(message)) {
|
||
|
OSyncError *error = NULL;
|
||
|
osync_demarshal_error(message, &error);
|
||
|
osync_error_duplicate(&engine->error, &error);
|
||
|
osync_debug("ENG", 1, "Connect command reply was a error: %s", osync_error_print(&error));
|
||
|
osync_status_update_member(engine, sender, MEMBER_CONNECT_ERROR, &error);
|
||
|
osync_error_update(&engine->error, "Unable to connect one of the members");
|
||
|
osync_flag_unset(sender->fl_connected);
|
||
|
osync_flag_set(sender->fl_finished);
|
||
|
osync_flag_set(sender->fl_sent_changes);
|
||
|
osync_flag_set(sender->fl_done);
|
||
|
/*
|
||
|
* FIXME: For now we want to stop the engine if
|
||
|
* one of the member didnt connect yet. Later it should
|
||
|
* be that if >= 2 members connect, the sync should continue
|
||
|
*/
|
||
|
osync_flag_set(engine->fl_stop);
|
||
|
|
||
|
} else {
|
||
|
osync_member_read_sink_info(sender->member, message);
|
||
|
|
||
|
osync_status_update_member(engine, sender, MEMBER_CONNECTED, NULL);
|
||
|
osync_flag_set(sender->fl_connected);
|
||
|
}
|
||
|
|
||
|
osengine_client_decider(engine, sender);
|
||
|
osync_trace(TRACE_EXIT, "_connect_reply_receiver");
|
||
|
}
|
||
|
|
||
|
void _sync_done_reply_receiver(OSyncMessage *message, OSyncClient *sender)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "_sync_done_reply_receiver(%p, %p)", message, sender);
|
||
|
|
||
|
OSyncEngine *engine = sender->engine;
|
||
|
|
||
|
if (osync_message_is_error(message)) {
|
||
|
OSyncError *error = NULL;
|
||
|
osync_demarshal_error(message, &error);
|
||
|
osync_error_duplicate(&engine->error, &error);
|
||
|
osync_debug("ENG", 1, "Sync done command reply was a error: %s", osync_error_print(&error));
|
||
|
osync_status_update_member(engine, sender, MEMBER_SYNC_DONE_ERROR, &error);
|
||
|
osync_error_update(&engine->error, "Unable to finish the sync for one of the members");
|
||
|
}
|
||
|
|
||
|
osync_flag_set(sender->fl_done);
|
||
|
osengine_client_decider(engine, sender);
|
||
|
osync_trace(TRACE_EXIT, "_sync_done_reply_receiver");
|
||
|
}
|
||
|
|
||
|
void _committed_all_reply_receiver(OSyncMessage *message, OSyncClient *sender)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, message, sender);
|
||
|
|
||
|
OSyncEngine *engine = sender->engine;
|
||
|
|
||
|
if (osync_message_is_error(message)) {
|
||
|
OSyncError *error = NULL;
|
||
|
osync_demarshal_error(message, &error);
|
||
|
osync_error_duplicate(&engine->error, &error);
|
||
|
osync_debug("ENG", 1, "Committed all command reply was a error: %s", osync_error_print(&error));
|
||
|
osync_status_update_member(engine, sender, MEMBER_COMMITTED_ALL_ERROR, &error);
|
||
|
osync_error_update(&engine->error, "Unable to write changes to one of the members");
|
||
|
} else
|
||
|
osync_status_update_member(engine, sender, MEMBER_COMMITTED_ALL, NULL);
|
||
|
|
||
|
osync_flag_set(sender->fl_committed_all);
|
||
|
osengine_client_decider(engine, sender);
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
}
|
||
|
|
||
|
void _disconnect_reply_receiver(OSyncMessage *message, OSyncClient *sender)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "_disconnect_reply_receiver(%p, %p)", message, sender);
|
||
|
|
||
|
OSyncEngine *engine = sender->engine;
|
||
|
|
||
|
if (osync_message_is_error(message)) {
|
||
|
OSyncError *error = NULL;
|
||
|
osync_demarshal_error(message, &error);
|
||
|
osync_debug("ENG", 1, "Sync done command reply was a error: %s", osync_error_print(&error));
|
||
|
osync_status_update_member(engine, sender, MEMBER_DISCONNECT_ERROR, &error);
|
||
|
} else
|
||
|
osync_status_update_member(engine, sender, MEMBER_DISCONNECTED, NULL);
|
||
|
|
||
|
osync_flag_unset(sender->fl_connected);
|
||
|
osync_flag_set(sender->fl_finished);
|
||
|
osengine_client_decider(engine, sender);
|
||
|
osync_trace(TRACE_EXIT, "_disconnect_reply_receiver");
|
||
|
}
|
||
|
|
||
|
void _get_change_data_reply_receiver(OSyncMessage *message, OSyncMappingEntry *entry)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "_get_change_data_reply_receiver(%p, %p, %p)", message, entry);
|
||
|
OSyncEngine *engine = entry->client->engine;
|
||
|
|
||
|
if (osync_message_is_error(message)) {
|
||
|
OSyncError *error = NULL;
|
||
|
osync_demarshal_error(message, &error);
|
||
|
osync_error_duplicate(&engine->error, &error);
|
||
|
osync_debug("MAP", 1, "Commit change command reply was a error: %s", osync_error_print(&error));
|
||
|
osync_status_update_change(engine, entry->change, CHANGE_RECV_ERROR, &error);
|
||
|
osync_error_update(&engine->error, "Unable to read one or more objects");
|
||
|
|
||
|
//FIXME Do we need to do anything here?
|
||
|
//osync_flag_unset(entry->fl_has_data);
|
||
|
} else {
|
||
|
|
||
|
osync_demarshal_changedata(message, entry->change);
|
||
|
|
||
|
osync_flag_set(entry->fl_has_data);
|
||
|
osync_status_update_change(engine, entry->change, CHANGE_RECEIVED, NULL);
|
||
|
}
|
||
|
|
||
|
osync_change_save(entry->change, TRUE, NULL);
|
||
|
osengine_mappingentry_decider(engine, entry);
|
||
|
osync_trace(TRACE_EXIT, "_get_change_data_reply_receiver");
|
||
|
}
|
||
|
|
||
|
void _read_change_reply_receiver(OSyncClient *sender, OSyncMessage *message, OSyncEngine *engine)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "_read_change_reply_receiver(%p, %p, %p)", sender, message, engine);
|
||
|
|
||
|
/*OSyncMappingEntry *entry = osync_message_get_data(message, "entry");
|
||
|
|
||
|
osync_flag_detach(entry->fl_read);
|
||
|
|
||
|
osync_flag_unset(entry->mapping->fl_solved);
|
||
|
osync_flag_unset(entry->mapping->fl_chkconflict);
|
||
|
osync_flag_unset(entry->mapping->fl_multiplied);
|
||
|
|
||
|
if (osync_change_get_changetype(entry->change) == CHANGE_DELETED)
|
||
|
osync_flag_set(entry->fl_deleted);
|
||
|
|
||
|
osync_flag_set(entry->fl_has_info);
|
||
|
osync_flag_unset(entry->fl_synced);
|
||
|
|
||
|
osync_change_save(entry->change, TRUE, NULL);
|
||
|
|
||
|
osync_status_update_change(engine, entry->change, CHANGE_RECEIVED, NULL);
|
||
|
|
||
|
osengine_mappingentry_decider(engine, entry);*/
|
||
|
osync_trace(TRACE_EXIT, "_read_change_reply_receiver");
|
||
|
}
|
||
|
|
||
|
void _commit_change_reply_receiver(OSyncMessage *message, OSyncMappingEntry *entry)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "_commit_change_reply_receiver(%p, %p)", message, entry);
|
||
|
OSyncEngine *engine = entry->client->engine;
|
||
|
|
||
|
if (osync_message_is_error(message)) {
|
||
|
OSyncError *error = NULL;
|
||
|
osync_demarshal_error(message, &error);
|
||
|
osync_error_duplicate(&engine->error, &error);
|
||
|
osync_debug("MAP", 1, "Commit change command reply was a error: %s", osync_error_print(&error));
|
||
|
osync_status_update_change(engine, entry->change, CHANGE_WRITE_ERROR, &error);
|
||
|
OSyncError *maperror = NULL;
|
||
|
osync_error_duplicate(&maperror, &error);
|
||
|
osync_status_update_mapping(engine, entry->mapping, MAPPING_WRITE_ERROR, &maperror);
|
||
|
osync_error_update(&engine->error, "Unable to write one or more objects");
|
||
|
|
||
|
//FIXME Do we need to do anything here?
|
||
|
osync_flag_unset(entry->fl_dirty);
|
||
|
osync_flag_set(entry->fl_synced);
|
||
|
} else {
|
||
|
/* The plugin may have generated a new UID after committing the change. The commit
|
||
|
* change reply will return the new UID of the change
|
||
|
*/
|
||
|
|
||
|
char *newuid;
|
||
|
osync_message_read_string(message, &newuid);
|
||
|
osync_change_set_uid(entry->change, newuid);
|
||
|
|
||
|
osync_status_update_change(engine, entry->change, CHANGE_SENT, NULL);
|
||
|
osync_flag_unset(entry->fl_dirty);
|
||
|
osync_flag_set(entry->fl_synced);
|
||
|
}
|
||
|
|
||
|
if (osync_change_get_changetype(entry->change) == CHANGE_DELETED)
|
||
|
osync_flag_set(entry->fl_deleted);
|
||
|
|
||
|
osync_change_reset(entry->change);
|
||
|
|
||
|
OSyncError *error = NULL;
|
||
|
osync_change_save(entry->change, TRUE, &error);
|
||
|
|
||
|
osengine_mappingentry_decider(engine, entry);
|
||
|
osync_trace(TRACE_EXIT, "_commit_change_reply_receiver");
|
||
|
}
|
||
|
|
||
|
OSyncClient *osync_client_new(OSyncEngine *engine, OSyncMember *member, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, engine, member, error);
|
||
|
OSyncClient *client = osync_try_malloc0(sizeof(OSyncClient), error);
|
||
|
if (!client)
|
||
|
goto error;
|
||
|
|
||
|
client->member = member;
|
||
|
osync_member_set_data(member, client);
|
||
|
client->engine = engine;
|
||
|
engine->clients = g_list_append(engine->clients, client);
|
||
|
|
||
|
char *name = g_strdup_printf("%s/pluginpipe", osync_member_get_configdir(member));
|
||
|
client->commands_to_osplugin = osync_queue_new(name, error);
|
||
|
g_free(name);
|
||
|
|
||
|
name = g_strdup_printf("%s/enginepipe", osync_member_get_configdir(member));
|
||
|
client->commands_from_osplugin = osync_queue_new(name, error);
|
||
|
g_free(name);
|
||
|
|
||
|
if (!client->commands_to_osplugin || !client->commands_from_osplugin)
|
||
|
goto error_free_client;
|
||
|
|
||
|
client->fl_connected = osync_flag_new(engine->cmb_connected);
|
||
|
client->fl_sent_changes = osync_flag_new(engine->cmb_sent_changes);
|
||
|
client->fl_done = osync_flag_new(NULL);
|
||
|
client->fl_committed_all = osync_flag_new(engine->cmb_committed_all_sent);
|
||
|
client->fl_finished = osync_flag_new(engine->cmb_finished);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s: %p", __func__, client);
|
||
|
return client;
|
||
|
|
||
|
error_free_client:
|
||
|
g_free(client);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void osync_client_reset(OSyncClient *client)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, client);
|
||
|
osync_flag_set_state(client->fl_connected, FALSE);
|
||
|
osync_flag_set_state(client->fl_sent_changes, FALSE);
|
||
|
osync_flag_set_state(client->fl_done, FALSE);
|
||
|
osync_flag_set_state(client->fl_finished, FALSE);
|
||
|
osync_flag_set_state(client->fl_committed_all, FALSE);
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
}
|
||
|
|
||
|
void osync_client_free(OSyncClient *client)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, client);
|
||
|
osync_queue_free(client->commands_to_osplugin);
|
||
|
osync_queue_free(client->commands_from_osplugin);
|
||
|
|
||
|
osync_flag_free(client->fl_connected);
|
||
|
osync_flag_free(client->fl_sent_changes);
|
||
|
osync_flag_free(client->fl_done);
|
||
|
osync_flag_free(client->fl_finished);
|
||
|
osync_flag_free(client->fl_committed_all);
|
||
|
|
||
|
g_free(client);
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
}
|
||
|
|
||
|
void *osync_client_message_sink(OSyncMember *member, const char *name, void *data, osync_bool synchronous)
|
||
|
{
|
||
|
OSyncClient *client = osync_member_get_data(member);
|
||
|
OSyncEngine *engine = client->engine;
|
||
|
if (!synchronous) {
|
||
|
/*OSyncMessage *message = itm_message_new_signal(client, "PLUGIN_MESSAGE");
|
||
|
osync_debug("CLI", 3, "Sending message %p PLUGIN_MESSAGE for message %s", message, name);
|
||
|
itm_message_set_data(message, "data", data);
|
||
|
itm_message_set_data(message, "name", g_strdup(name));
|
||
|
itm_queue_send(engine->incoming, message);*/
|
||
|
return NULL;
|
||
|
} else {
|
||
|
return engine->plgmsg_callback(engine, client, name, data, engine->plgmsg_userdata);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OSyncPluginTimeouts osync_client_get_timeouts(OSyncClient *client)
|
||
|
{
|
||
|
return osync_plugin_get_timeouts(osync_member_get_plugin(client->member));
|
||
|
}
|
||
|
|
||
|
void osync_client_call_plugin(OSyncClient *client, char *function, void *data, OSyncPluginReplyHandler replyhandler, void *userdata)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %s, %p, %p, %p)", __func__, client, function, data, replyhandler, userdata);
|
||
|
|
||
|
/*OSyncEngine *engine = client->engine;
|
||
|
ITMessage *message = itm_message_new_methodcall(engine, "CALL_PLUGIN");
|
||
|
itm_message_set_data(message, "data", data);
|
||
|
itm_message_set_data(message, "function", g_strdup(function));
|
||
|
|
||
|
if (replyhandler) {
|
||
|
OSyncPluginCallContext *ctx = g_malloc0(sizeof(OSyncPluginCallContext));
|
||
|
ctx->handler = replyhandler;
|
||
|
ctx->userdata = userdata;
|
||
|
itm_message_set_handler(message, engine->incoming, (ITMessageHandler)_recv_plugin_answer, ctx);
|
||
|
|
||
|
itm_message_set_data(message, "want_reply", GINT_TO_POINTER(1));
|
||
|
} else
|
||
|
itm_message_set_data(message, "want_reply", GINT_TO_POINTER(0));
|
||
|
|
||
|
itm_queue_send(client->incoming, message);*/
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_get_changes(OSyncClient *target, OSyncEngine *sender, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, target, sender, error);
|
||
|
|
||
|
osync_flag_changing(target->fl_sent_changes);
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_GET_CHANGES, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
osync_message_set_handler(message, (OSyncMessageHandler)_get_changes_reply_receiver, target);
|
||
|
|
||
|
osync_member_write_sink_info(target->member, message);
|
||
|
|
||
|
OSyncPluginTimeouts timeouts = osync_client_get_timeouts(target);
|
||
|
if (!osync_queue_send_message_with_timeout(target->commands_to_osplugin, target->commands_from_osplugin, message, timeouts.get_changeinfo_timeout, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_get_change_data(OSyncClient *target, OSyncEngine *sender, OSyncMappingEntry *entry, OSyncError **error)
|
||
|
{
|
||
|
osync_flag_changing(entry->fl_has_data);
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_GET_CHANGEDATA, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
osync_message_set_handler(message, (OSyncMessageHandler)_get_change_data_reply_receiver, entry);
|
||
|
|
||
|
osync_marshal_change(message, entry->change);
|
||
|
|
||
|
osync_debug("ENG", 3, "Sending get_changedata message %p to client %p", message, entry->client);
|
||
|
|
||
|
OSyncPluginTimeouts timeouts = osync_client_get_timeouts(target);
|
||
|
if (!osync_queue_send_message_with_timeout(target->commands_to_osplugin, target->commands_from_osplugin, message, timeouts.get_data_timeout, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/*void osync_client_read_change(OSyncEngine *sender, OSyncMappingEntry *entry)
|
||
|
{
|
||
|
//osync_flag_changing(entry->fl_has_data);
|
||
|
OSyncMessage *message = osync_message_new_methodcall(sender, "READ_CHANGE");
|
||
|
osync_message_set_handler(message, sender->incoming, (OSyncMessageHandler)_read_change_reply_receiver, sender);
|
||
|
osync_message_set_data(message, "change", entry->change);
|
||
|
osync_message_set_data(message, "entry", entry);
|
||
|
osync_debug("ENG", 3, "Sending read_change message %p to client %p", message, entry->client);
|
||
|
|
||
|
OSyncPluginTimeouts timeouts = osync_client_get_timeouts(entry->client);
|
||
|
osync_queue_send_with_timeout(entry->client->incoming, message, timeouts.read_change_timeout, sender);
|
||
|
}*/
|
||
|
|
||
|
osync_bool osync_client_connect(OSyncClient *target, OSyncEngine *sender, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, target, sender, error);
|
||
|
|
||
|
osync_flag_changing(target->fl_connected);
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_CONNECT, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
osync_member_write_sink_info(target->member, message);
|
||
|
|
||
|
osync_message_set_handler(message, (OSyncMessageHandler)_connect_reply_receiver, target);
|
||
|
|
||
|
OSyncPluginTimeouts timeouts = osync_client_get_timeouts(target);
|
||
|
if (!osync_queue_send_message_with_timeout(target->commands_to_osplugin, target->commands_from_osplugin, message, timeouts.connect_timeout, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_commit_change(OSyncClient *target, OSyncEngine *sender, OSyncMappingEntry *entry, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, target, sender, entry);
|
||
|
osync_trace(TRACE_INTERNAL, "Committing change with uid %s, changetype %i, data %p, size %i, objtype %s and format %s from member %lli", osync_change_get_uid(entry->change), osync_change_get_changetype(entry->change), osync_change_get_data(entry->change), osync_change_get_datasize(entry->change), osync_change_get_objtype(entry->change) ? osync_objtype_get_name(osync_change_get_objtype(entry->change)) : "None", osync_change_get_objformat(entry->change) ? osync_objformat_get_name(osync_change_get_objformat(entry->change)) : "None", osync_member_get_id(entry->client->member));
|
||
|
|
||
|
osync_flag_changing(entry->fl_dirty);
|
||
|
|
||
|
// convert the data to the format accepted by the member
|
||
|
if (!osync_change_convert_member_sink(osync_group_get_format_env(sender->group), entry->change, target->member, error))
|
||
|
goto error;
|
||
|
|
||
|
if (osync_change_get_changetype(entry->change) == CHANGE_ADDED) {
|
||
|
int elevated = 0;
|
||
|
// Generate a new UID, if necessary
|
||
|
OSyncMappingView *view = osengine_mappingtable_find_view(sender->maptable, target->member);
|
||
|
while (!osengine_mappingview_uid_is_unique(view, entry, TRUE)) {
|
||
|
if (!osync_change_elevate(sender, entry->change, 1))
|
||
|
break;
|
||
|
elevated++;
|
||
|
}
|
||
|
|
||
|
if (elevated) {
|
||
|
// Save the newly generated UID
|
||
|
if (!osync_change_save(entry->change, TRUE, error))
|
||
|
goto error;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_COMMIT_CHANGE, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
osync_marshal_change(message, entry->change);
|
||
|
|
||
|
osync_message_set_handler(message, (OSyncMessageHandler)_commit_change_reply_receiver, entry);
|
||
|
OSyncPluginTimeouts timeouts = osync_client_get_timeouts(entry->client);
|
||
|
|
||
|
if (!osync_queue_send_message_with_timeout(target->commands_to_osplugin, target->commands_from_osplugin, message, timeouts.commit_timeout, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
g_assert(osync_flag_is_attached(entry->fl_committed) == TRUE);
|
||
|
osync_flag_detach(entry->fl_committed);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_sync_done(OSyncClient *target, OSyncEngine *sender, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, target, sender, error);
|
||
|
|
||
|
osync_flag_changing(target->fl_done);
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_SYNC_DONE, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
osync_message_set_handler(message, (OSyncMessageHandler)_sync_done_reply_receiver, target);
|
||
|
|
||
|
OSyncPluginTimeouts timeouts = osync_client_get_timeouts(target);
|
||
|
if (!osync_queue_send_message_with_timeout(target->commands_to_osplugin, target->commands_from_osplugin, message, timeouts.sync_done_timeout, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_committed_all(OSyncClient *target, OSyncEngine *sender, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, target, sender);
|
||
|
|
||
|
osync_flag_changing(target->fl_committed_all);
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_COMMITTED_ALL, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
osync_message_set_handler(message, (OSyncMessageHandler)_committed_all_reply_receiver, target);
|
||
|
|
||
|
//OSyncPluginTimeouts timeouts = osync_client_get_timeouts(target);
|
||
|
/*FIXME: Add timeout to committed_all message */
|
||
|
if (!osync_queue_send_message(target->commands_to_osplugin, target->commands_from_osplugin, message, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_disconnect(OSyncClient *target, OSyncEngine *sender, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, target, sender);
|
||
|
|
||
|
osync_flag_changing(target->fl_connected);
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_DISCONNECT, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
osync_message_set_handler(message, (OSyncMessageHandler)_disconnect_reply_receiver, target);
|
||
|
|
||
|
OSyncPluginTimeouts timeouts = osync_client_get_timeouts(target);
|
||
|
if (!osync_queue_send_message_with_timeout(target->commands_to_osplugin, target->commands_from_osplugin, message, timeouts.disconnect_timeout, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
void osync_client_call_plugin_with_reply(OSyncClient *client, char *function, void *data, void ( *replyhandler)(OSyncEngine *, OSyncClient *, void *, OSyncError *), int timeout)
|
||
|
{
|
||
|
OSyncEngine *engine = client->engine;
|
||
|
ITMessage *message = itm_message_new_signal(engine, "CALL_PLUGIN");
|
||
|
osync_debug("CLI", 3, "Sending message %p CALL_PLUGIN for function %s", message, function);
|
||
|
itm_message_set_data(message, "data", data);
|
||
|
itm_message_set_data(message, "function", g_strdup(function));
|
||
|
itm_queue_send_with_reply(client->incoming, message);
|
||
|
}*/
|
||
|
|
||
|
char *osync_client_pid_filename(OSyncClient *client)
|
||
|
{
|
||
|
return g_strdup_printf("%s/osplugin.pid", client->member->configdir);
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_remove_pidfile(OSyncClient *client, OSyncError **error)
|
||
|
{
|
||
|
osync_bool ret = FALSE;
|
||
|
char *pidpath = osync_client_pid_filename(client);
|
||
|
|
||
|
if (unlink(pidpath) < 0) {
|
||
|
osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't remove pid file: %s", strerror(errno));
|
||
|
goto out_free_path;
|
||
|
}
|
||
|
|
||
|
/* Success */
|
||
|
ret = TRUE;
|
||
|
|
||
|
out_free_path:
|
||
|
g_free(pidpath);
|
||
|
//out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_create_pidfile(OSyncClient *client, OSyncError **error)
|
||
|
{
|
||
|
osync_bool ret = FALSE;
|
||
|
char *pidpath = osync_client_pid_filename(client);
|
||
|
char *pidstr = g_strdup_printf("%ld", (long)client->child_pid);
|
||
|
|
||
|
if (!osync_file_write(pidpath, pidstr, strlen(pidstr), 0644, error))
|
||
|
goto out_free_pidstr;
|
||
|
|
||
|
/* Success */
|
||
|
ret = TRUE;
|
||
|
|
||
|
out_free_pidstr:
|
||
|
g_free(pidstr);
|
||
|
//out_free_path:
|
||
|
g_free(pidpath);
|
||
|
//out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_kill_old_osplugin(OSyncClient *client, OSyncError **error)
|
||
|
{
|
||
|
osync_bool ret = FALSE;
|
||
|
|
||
|
char *pidstr;
|
||
|
int pidlen;
|
||
|
pid_t pid;
|
||
|
|
||
|
char *pidpath = osync_client_pid_filename(client);
|
||
|
|
||
|
/* Simply returns if there is no PID file */
|
||
|
if (!g_file_test(pidpath, G_FILE_TEST_EXISTS)) {
|
||
|
ret = TRUE;
|
||
|
goto out_free_path;
|
||
|
}
|
||
|
|
||
|
if (!osync_file_read(pidpath, &pidstr, &pidlen, error))
|
||
|
goto out_free_path;
|
||
|
|
||
|
pid = atol(pidstr);
|
||
|
if (!pid)
|
||
|
goto out_free_str;
|
||
|
|
||
|
osync_trace(TRACE_INTERNAL, "Killing old osplugin process. PID: %ld", (long)pid);
|
||
|
|
||
|
if (kill(pid, SIGTERM) < 0) {
|
||
|
osync_trace(TRACE_INTERNAL, "Error killing old osplugin: %s. Stale pid file?", strerror(errno));
|
||
|
/* Don't return failure if kill() failed, because it may be a stale pid file */
|
||
|
}
|
||
|
|
||
|
int count = 0;
|
||
|
while (osync_queue_is_alive(client->commands_to_osplugin)) {
|
||
|
if (count++ > 10) {
|
||
|
osync_trace(TRACE_INTERNAL, "Killing old osplugin process with SIGKILL");
|
||
|
kill(pid, SIGKILL);
|
||
|
break;
|
||
|
}
|
||
|
osync_trace(TRACE_INTERNAL, "Waiting for other side to terminate");
|
||
|
/*FIXME: Magic numbers are evil */
|
||
|
usleep(500000);
|
||
|
}
|
||
|
|
||
|
if (unlink(pidpath) < 0) {
|
||
|
osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't erase PID file: %s", strerror(errno));
|
||
|
goto out_free_str;
|
||
|
}
|
||
|
|
||
|
/* Success */
|
||
|
ret = TRUE;
|
||
|
|
||
|
out_free_str:
|
||
|
g_free(pidstr);
|
||
|
out_free_path:
|
||
|
g_free(pidpath);
|
||
|
//out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
osync_bool osync_client_spawn(OSyncClient *client, OSyncEngine *engine, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, client, engine, error);
|
||
|
|
||
|
int waiting = 0;
|
||
|
|
||
|
if (!osync_client_kill_old_osplugin(client, error))
|
||
|
goto error;
|
||
|
|
||
|
if (!osync_queue_exists(client->commands_to_osplugin) || !osync_queue_is_alive(client->commands_to_osplugin)) {
|
||
|
pid_t cpid = fork();
|
||
|
if (cpid == 0) {
|
||
|
osync_trace_reset_indent();
|
||
|
|
||
|
/* Export all options to osplugin through environment variables */
|
||
|
osync_env_export_all_options(osync_group_get_env(engine->group));
|
||
|
|
||
|
OSyncMember *member = client->member;
|
||
|
OSyncPlugin *plugin = osync_member_get_plugin(member);
|
||
|
const char *path = osync_plugin_get_path(plugin);
|
||
|
setenv("OSYNC_MODULE_LIST", path, 1);
|
||
|
|
||
|
osync_env_export_loaded_modules(osync_group_get_env(engine->group));
|
||
|
|
||
|
char *memberstring = g_strdup_printf("%lli", osync_member_get_id(client->member));
|
||
|
execlp(OSPLUGIN, OSPLUGIN, osync_group_get_configdir(engine->group), memberstring, NULL);
|
||
|
|
||
|
if (errno == ENOENT) {
|
||
|
execlp("./osplugin", "osplugin", osync_group_get_configdir(engine->group), memberstring, NULL);
|
||
|
}
|
||
|
|
||
|
osync_trace(TRACE_INTERNAL, "unable to exec");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
client->child_pid = cpid;
|
||
|
|
||
|
/* We are going to wait 5 seconds for plugin */
|
||
|
while (!osync_queue_exists(client->commands_to_osplugin) && waiting <= 5) {
|
||
|
osync_trace(TRACE_INTERNAL, "Waiting for other side to create fifo");
|
||
|
|
||
|
sleep(1);
|
||
|
waiting++;
|
||
|
}
|
||
|
|
||
|
osync_trace(TRACE_INTERNAL, "Queue was created");
|
||
|
}
|
||
|
|
||
|
if (client->child_pid) {
|
||
|
if (!osync_client_create_pidfile(client, error))
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
if (!osync_queue_connect(client->commands_to_osplugin, OSYNC_QUEUE_SENDER, error))
|
||
|
goto error;
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_INITIALIZE, 0, error);
|
||
|
if (!message)
|
||
|
goto error_disconnect;
|
||
|
|
||
|
osync_message_write_string(message, client->commands_from_osplugin->name);
|
||
|
|
||
|
if (!osync_queue_send_message(client->commands_to_osplugin, NULL, message, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error_disconnect:
|
||
|
osync_queue_disconnect(client->commands_to_osplugin, NULL);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_init(OSyncClient *client, OSyncEngine *engine, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, client, engine, error);
|
||
|
|
||
|
OSyncMessage *reply = osync_queue_get_message(client->commands_from_osplugin);
|
||
|
|
||
|
osync_trace(TRACE_INTERNAL, "reply received %i", reply->cmd);
|
||
|
if (reply->cmd == OSYNC_MESSAGE_ERRORREPLY) {
|
||
|
if (error)
|
||
|
osync_demarshal_error(reply, error);
|
||
|
goto error_free_reply;
|
||
|
}
|
||
|
|
||
|
if (reply->cmd != OSYNC_MESSAGE_REPLY) {
|
||
|
osync_error_set(error, OSYNC_ERROR_GENERIC, "Invalid answer from plugin process");
|
||
|
goto error_free_reply;
|
||
|
}
|
||
|
|
||
|
osync_message_unref(reply);
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_reply:
|
||
|
osync_message_unref(reply);
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
osync_bool osync_client_finalize(OSyncClient *client, OSyncError **error)
|
||
|
{
|
||
|
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, client, error);
|
||
|
|
||
|
OSyncMessage *message = osync_message_new(OSYNC_MESSAGE_FINALIZE, 0, error);
|
||
|
if (!message)
|
||
|
goto error;
|
||
|
|
||
|
if (!osync_queue_send_message(client->commands_to_osplugin, NULL, message, error))
|
||
|
goto error_free_message;
|
||
|
|
||
|
osync_message_unref(message);
|
||
|
|
||
|
if (client->child_pid) {
|
||
|
int status;
|
||
|
if (waitpid(client->child_pid, &status, 0) == -1) {
|
||
|
osync_error_set(error, OSYNC_ERROR_GENERIC, "Error waiting for osplugin process: %s", strerror(errno));
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
if (!WIFEXITED(status))
|
||
|
osync_trace(TRACE_INTERNAL, "Child has exited abnormally");
|
||
|
else if (WEXITSTATUS(status) != 0)
|
||
|
osync_trace(TRACE_INTERNAL, "Child has returned non-zero exit status (%d)", WEXITSTATUS(status));
|
||
|
|
||
|
if (!osync_client_remove_pidfile(client, error))
|
||
|
goto error;
|
||
|
}
|
||
|
|
||
|
osync_queue_disconnect(client->commands_to_osplugin, NULL);
|
||
|
|
||
|
|
||
|
osync_trace(TRACE_EXIT, "%s", __func__);
|
||
|
return TRUE;
|
||
|
|
||
|
error_free_message:
|
||
|
osync_message_unref(message);
|
||
|
error:
|
||
|
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
|
||
|
return FALSE;
|
||
|
}
|