#include "gnunet_constants.h"
#include "gnunet_arm_service.h"
#include "gnunet_namestore_service.h"
-
+#include "namestore.h"
#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING
#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
char *data; /*stub data pointer*/
};
+
+/**
+ * Message in linked list we should send to the service. The
+ * actual binary message follows this struct.
+ */
+struct PendingMessage
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct PendingMessage *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct PendingMessage *prev;
+
+ /**
+ * Size of the message.
+ */
+ size_t size;
+
+ /**
+ * Is this the 'START' message?
+ */
+ int is_init;
+};
+
+
/**
* Connection to the NAMESTORE service.
*/
*/
struct GNUNET_CLIENT_TransmitHandle *th;
- /* dll to use for records */
- struct GNUNET_NAMESTORE_SimpleRecord * records_head;
- struct GNUNET_NAMESTORE_SimpleRecord * records_tail;
+ /**
+ * Reconnect task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+ struct PendingMessage * pending_head;
+ struct PendingMessage * pending_tail;
+ /**
+ * Should we reconnect to service due to some serious error?
+ */
+ int reconnect;
};
struct GNUNET_NAMESTORE_SimpleRecord
const void *data;
};
+/**
+ * Disconnect from service and then reconnect.
+ *
+ * @param nsh our handle
+ */
+static void
+force_reconnect (struct GNUNET_NAMESTORE_Handle *nsh);
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param nsh handle to use
+ */
+static void
+do_transmit (struct GNUNET_NAMESTORE_Handle *nsh);
+
+/**
+ * We can now transmit a message to NAMESTORE. Do it.
+ *
+ * @param cls the 'struct GNUNET_NAMESTORE_Handle'
+ * @param size number of bytes we can transmit
+ * @param buf where to copy the messages
+ * @return number of bytes copied into buf
+ */
+static size_t
+transmit_message_to_namestore (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_NAMESTORE_Handle *nsh = cls;
+ struct PendingMessage *p;
+ size_t ret;
+ char *cbuf;
+
+ nsh->th = NULL;
+ if ((size == 0) || (buf == NULL))
+ {
+ force_reconnect (nsh);
+ return 0;
+ }
+ ret = 0;
+ cbuf = buf;
+ while ((NULL != (p = nsh->pending_head)) && (p->size <= size))
+ {
+ memcpy (&cbuf[ret], &p[1], p->size);
+ ret += p->size;
+ size -= p->size;
+ GNUNET_CONTAINER_DLL_remove (nsh->pending_head, nsh->pending_tail, p);
+ if (GNUNET_YES == p->is_init)
+ GNUNET_CLIENT_receive (nsh->client,/* &process_namestore_message*/ NULL, nsh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ GNUNET_free (p);
+ }
+ do_transmit (nsh);
+ return ret;
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param nsh handle to use
+ */
+static void
+do_transmit (struct GNUNET_NAMESTORE_Handle *nsh)
+{
+ struct PendingMessage *p;
+
+ if (NULL != nsh->th)
+ return;
+ if (NULL == (p = nsh->pending_head))
+ return;
+ if (NULL == nsh->client)
+ return; /* currently reconnecting */
+ nsh->th = GNUNET_CLIENT_notify_transmit_ready (nsh->client, p->size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_NO, &transmit_message_to_namestore,
+ nsh);
+}
+
+
+/**
+ * Try again to connect to namestore service.
+ *
+ * @param cls the handle to the namestore service
+ * @param tc scheduler context
+ */
+static void
+reconnect (struct GNUNET_NAMESTORE_Handle *nsh)
+{
+ struct PendingMessage *p;
+ struct StartMessage *init;
+
+ GNUNET_assert (NULL == nsh->client);
+ nsh->client = GNUNET_CLIENT_connect ("namestore", nsh->cfg);
+ GNUNET_assert (NULL != nsh->client);
+
+ if ((NULL == (p = nsh->pending_head)) || (GNUNET_YES != p->is_init))
+ {
+ p = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct StartMessage));
+ p->size = sizeof (struct StartMessage);
+ p->is_init = GNUNET_YES;
+ init = (struct StartMessage *) &p[1];
+ init->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_START);
+ init->header.size = htons (sizeof (struct StartMessage));
+ GNUNET_CONTAINER_DLL_insert (nsh->pending_head, nsh->pending_tail, p);
+ }
+ do_transmit (nsh);
+}
+
+/**
+ * Re-establish the connection to the service.
+ *
+ * @param cls handle to use to re-connect.
+ * @param tc scheduler context
+ */
+static void
+reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_NAMESTORE_Handle *nsh = cls;
+
+ nsh->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ reconnect (nsh);
+}
+
+
+/**
+ * Disconnect from service and then reconnect.
+ *
+ * @param nsh our handle
+ */
+static void
+force_reconnect (struct GNUNET_NAMESTORE_Handle *nsh)
+{
+ nsh->reconnect = GNUNET_NO;
+ GNUNET_CLIENT_disconnect (nsh->client, GNUNET_NO);
+ nsh->client = NULL;
+ nsh->reconnect_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
+ nsh);
+}
+
+
+
/**
* Initialize the connection with the NAMESTORE service.
*
struct GNUNET_NAMESTORE_Handle *
GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- struct GNUNET_NAMESTORE_Handle *handle;
+ struct GNUNET_NAMESTORE_Handle *nsh;
- handle = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Handle));
- handle->cfg = cfg;
- return handle;
+ nsh = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Handle));
+ nsh->cfg = cfg;
+ nsh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, nsh);
+ return nsh;
}
{
struct GNUNET_NAMESTORE_QueueEntry *qe;
qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry));
-
+#if 0
struct GNUNET_NAMESTORE_SimpleRecord *sr;
sr = GNUNET_malloc(sizeof(struct GNUNET_NAMESTORE_SimpleRecord));
sr->name = name;
sr->data_size = data_size;
sr->data = data;
GNUNET_CONTAINER_DLL_insert(h->records_head, h->records_tail, sr);
+#endif
return qe;
}
{
struct GNUNET_NAMESTORE_QueueEntry *qe;
qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry));
-
+#if 0
struct GNUNET_NAMESTORE_SimpleRecord *iter;
for (iter=h->records_head; iter != NULL; iter=iter->next)
{
GNUNET_CONTAINER_DLL_remove(h->records_head,
h->records_tail,
iter);
-
+#endif
return qe;
}
{
struct GNUNET_NAMESTORE_QueueEntry *qe;
qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry));
-
+#if 0
struct GNUNET_NAMESTORE_SimpleRecord *iter;
for (iter=h->records_head; iter != NULL; iter=iter->next)
{
}
proc(proc_cls, zone, name, record_type,
GNUNET_TIME_absolute_get_forever(), 0, NULL, 0, NULL); /*TERMINATE*/
-
+#endif
return qe;
}