/**
* This file is part of GNUnet
* Copyright (C) 2013 GNUnet e.V.
*
* GNUnet is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* GNUnet 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
* Affero General Public License for more details.
*/
/**
* @file psycstore/gnunet-service-psycstore.c
* @brief PSYCstore service
* @author Gabor X Toth
* @author Christian Grothoff
*/
#include <inttypes.h>
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_constants.h"
#include "gnunet_protocols.h"
#include "gnunet_statistics_service.h"
#include "gnunet_psyc_util_lib.h"
#include "gnunet_psycstore_service.h"
#include "gnunet_psycstore_plugin.h"
#include "psycstore.h"
/**
* Handle to our current configuration.
*/
static const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Service handle.
*/
static struct GNUNET_SERVICE_Handle *service;
/**
* Handle to the statistics service.
*/
static struct GNUNET_STATISTICS_Handle *stats;
/**
* Database handle
*/
static struct GNUNET_PSYCSTORE_PluginFunctions *db;
/**
* Name of the database plugin
*/
static char *db_lib_name;
/**
* Task run during shutdown.
*
* @param cls unused
*/
static void
shutdown_task (void *cls)
{
if (NULL != stats)
{
GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
stats = NULL;
}
GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db));
GNUNET_free (db_lib_name);
db_lib_name = NULL;
}
/**
* Send a result code back to the client.
*
* @param client
* Client that should receive the result code.
* @param result_code
* Code to transmit.
* @param op_id
* Operation ID in network byte order.
* @param err_msg
* Error message to include (or NULL for none).
*/
static void
send_result_code (struct GNUNET_SERVICE_Client *client,
uint64_t op_id,
int64_t result_code,
const char *err_msg)
{
struct OperationResult *res;
size_t err_size = 0;
if (NULL != err_msg)
err_size = strnlen (err_msg,
GNUNET_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1;
struct GNUNET_MQ_Envelope *
env = GNUNET_MQ_msg_extra (res, err_size,
GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE);
res->result_code = GNUNET_htonll (result_code - INT64_MIN);
res->op_id = op_id;
if (0 < err_size)
{
GNUNET_memcpy (&res[1], err_msg, err_size);
((char *) &res[1])[err_size - 1] = '\0';
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending result to client: %" PRId64 " (%s)\n",
result_code, err_msg);
GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
}
enum
{
MEMBERSHIP_TEST_NOT_NEEDED = 0,
MEMBERSHIP_TEST_NEEDED = 1,
MEMBERSHIP_TEST_DONE = 2,
} MessageMembershipTest;
struct SendClosure
{
struct GNUNET_SERVICE_Client *client;
/**
* Channel's public key.
*/
struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
/**
* Slave's public key.
*/
struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
/**
* Operation ID.
*/
uint64_t op_id;
/**
* Membership test result.
*/
int membership_test_result;
/**
* Do membership test with @a slave_key before returning fragment?
* @see enum MessageMembershipTest
*/
uint8_t membership_test;
};
static int
send_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg,
enum GNUNET_PSYCSTORE_MessageFlags flags)
{
struct SendClosure *sc = cls;
struct FragmentResult *res;
if (MEMBERSHIP_TEST_NEEDED == sc->membership_test)
{
sc->membership_test = MEMBERSHIP_TEST_DONE;
sc->membership_test_result
= db->membership_test (db->cls, &sc->channel_key, &sc->slave_key,
GNUNET_ntohll (msg->message_id));
switch (sc->membership_test_result)
{
case GNUNET_YES:
break;
case GNUNET_NO:
case GNUNET_SYSERR:
return GNUNET_NO;
}
}
size_t msg_size = ntohs (msg->header.size);
struct GNUNET_MQ_Envelope *
env = GNUNET_MQ_msg_extra (res, msg_size,
GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT);
res->op_id = sc->op_id;
res->psycstore_flags = htonl (flags);
GNUNET_memcpy