/*
* This file is part of GNUnet
* (C) 2013 Christian Grothoff (and other contributing authors)
*
* 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, 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNUnet; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* @file psyc/psyc_api.c
* @brief PSYC service; high-level access to the PSYC protocol
* note that clients of this API are NOT expected to
* understand the PSYC message format, only the semantics!
* Parsing (and serializing) the PSYC stream format is done
* within the implementation of the libgnunetpsyc library,
* and this API deliberately exposes as little as possible
* of the actual data stream format to the application!
* @author Gabor X Toth
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_env_lib.h"
#include "gnunet_psyc_service.h"
#include "psyc.h"
#define LOG(kind,...) GNUNET_log_from (kind, "psyc-api",__VA_ARGS__)
struct OperationHandle
{
struct OperationHandle *prev;
struct OperationHandle *next;
const struct GNUNET_MessageHeader *msg;
};
/**
* Handle to access PSYC channel operations for both the master and slaves.
*/
struct GNUNET_PSYC_Channel
{
/**
* Configuration to use.
*/
const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Socket (if available).
*/
struct GNUNET_CLIENT_Connection *client;
/**
* Currently pending transmission request, or NULL for none.
*/
struct GNUNET_CLIENT_TransmitHandle *th;
/**
* Head of operations to transmit.
*/
struct OperationHandle *transmit_head;
/**
* Tail of operations to transmit.
*/
struct OperationHandle *transmit_tail;
/**
* Message to send on reconnect.
*/
struct GNUNET_MessageHeader *reconnect_msg;
/**
* Task doing exponential back-off trying to reconnect.
*/
GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
/**
* Time for next connect retry.
*/
struct GNUNET_TIME_Relative reconnect_delay;
GNUNET_PSYC_Method method_cb;
GNUNET_PSYC_JoinCallback join_cb;
void *cb_cls;
/**
* Are we polling for incoming messages right now?
*/
int in_receive;
/**
* Are we currently transmitting a message?
*/
int in_transmit;
/**
* Is this a master or slave channel?
*/
int is_master;
/**
* Buffer space available for transmitting the next data fragment.
*/
uint16_t tmit_buf_avail;
};
/**
* Handle for a pending PSYC transmission operation.
*/
struct GNUNET_PSYC_MasterTransmitHandle
{
struct GNUNET_PSYC_Master *master;
GNUNET_PSYC_MasterTransmitNotify notify;
void *notify_cls;
enum GNUNET_PSYC_DataStatus status;
};
/**
* Handle for the master of a PSYC channel.
*/
struct GNUNET_PSYC_Master
{
struct GNUNET_PSYC_Channel ch;
struct GNUNET_PSYC_MasterTransmitHandle *tmit;
GNUNET_PSYC_MasterStartCallback start_cb;
uint64_t max_message_id;
};
/**
* Handle for a PSYC channel slave.
*/
struct GNUNET_PSYC_Slave
{
struct GNUNET_PSYC_Channel ch;
};
/**
* Handle that identifies a join request.
*
* Used to match calls to #GNUNET_PSYC_JoinCallback to the
* corresponding calls to GNUNET_PSYC_join_decision().
*/
struct GNUNET_PSYC_JoinHandle
{
};
/**
* Handle for a pending PSYC transmission operation.
*/
struct GNUNET_PSYC_SlaveTransmitHandle
{
};
/**
* Handle to a story telling operation.
*/
struct GNUNET_PSYC_Story
{
};
/**
* Handle for a state query operation.
*/
struct GNUNET_PSYC_StateQuery
{
};
/**
* Try again to connect to the PSYC service.
*
* @param cls Handle to the PSYC service.
* @param tc Scheduler context
*/
static void
reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
/**
* Reschedule a connect attempt to the service.
*
* @param h transport service to reconnect
*/
static void
reschedule_connect (struct GNUNET_PSYC_Channel *c)
{
GNUNET_assert (c->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
if (NULL != c->th)
{
GNUNET_CLIENT_notify_transmit_ready_cancel (c->th);
c->th = NULL;
}
if (NULL != c->client)
{
GNUNET_CLIENT_disconnect (c->client);
c->client = NULL;
}
c->in_receive = GNUNET_NO;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Scheduling task to reconnect to PSYC service in %s.\n",
GNUNET_STRINGS_relative_time_to_string (c->reconnect_delay, GNUNET_YES));
c->reconnect_task =
GNUNET_SCHEDULER_add_delayed (c->reconnect_delay, &reconnect, c);
c->reconnect_delay = GNUNET_TIME_STD_BACKOFF (c->reconnect_delay);
}
/**
* Schedule transmission of the next message from our queue.
*
* @param h PSYC handle
*/
static void
transmit_next (struct GNUNET_PSYC_Channel *c);
void
master_transmit_data (struct GNUNET_PSYC_Master *mst)
{
struct GNUNET_PSYC_Channel *ch = &mst->ch;
size_t data_size = ch->tmit_buf_avail;
struct GNUNET_PSYC_MessageData *pdata;