/*
This file is part of GNUnet.
- (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 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
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.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
/**
* @author Christian Grothoff
*/
#include "platform.h"
-#include "gnunet_client_lib.h"
+#include "gnunet_util_lib.h"
#include "gnunet_peerinfo_service.h"
#include "gnunet_protocols.h"
-#include "gnunet_time_lib.h"
#include "peerinfo.h"
+#define LOG(kind,...) GNUNET_log_from (kind, "peerinfo-api",__VA_ARGS__)
+
/**
* Context for the info handler.
*/
/**
* Our connection to the PEERINFO service.
*/
- struct GNUNET_CLIENT_Connection *client;
+ struct GNUNET_MQ_Handle *mq;
/**
* Function to call with information.
GNUNET_PEERINFO_Processor callback;
/**
- * Closure for callback.
+ * Closure for @e callback.
*/
void *callback_cls;
/**
- * Handle to our initial request for message transmission to
- * the peerinfo service.
+ * Configuration.
*/
- struct GNUNET_CLIENT_TransmitHandle *init;
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
- * Configuration.
+ * Tasked used for delayed re-connection attempt.
*/
- const struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_SCHEDULER_Task *task;
/**
- * Scheduler.
+ * Include friend only HELLOs in callbacks
*/
- struct GNUNET_SCHEDULER_Handle *sched;
+ int include_friend_only;
};
/**
- * Send a request to the peerinfo service to start being
- * notified about all changes to peer information.
+ * Task to re-try connecting to peerinfo.
*
- * @param nc our context
+ * @param cls the `struct GNUNET_PEERINFO_NotifyContext *`
*/
static void
-request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc);
+reconnect (void *cls);
/**
- * Read notifications from the client handle and pass them
- * to the callback.
+ * We encountered an error, reconnect to the service.
*
- * @param nc our context
+ * @param nc context to reconnect
*/
static void
-receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc);
+do_reconnect (struct GNUNET_PEERINFO_NotifyContext *nc)
+{
+ GNUNET_MQ_destroy (nc->mq);
+ nc->mq = NULL;
+ nc->task = GNUNET_SCHEDULER_add_now (&reconnect,
+ nc);
+}
/**
- * Receive a peerinfo information message, process it and
- * go for more.
+ * We got a disconnect after asking regex to do the announcement.
+ * Retry.
*
- * @param cls closure
- * @param msg message received, NULL on timeout or fatal error
+ * @param cls the `struct GNUNET_PEERINFO_NotifyContext` to retry
+ * @param error error code
*/
static void
-process_notification (void *cls,
- const struct
- GNUNET_MessageHeader * msg)
+mq_error_handler (void *cls,
+ enum GNUNET_MQ_Error error)
{
struct GNUNET_PEERINFO_NotifyContext *nc = cls;
- const struct InfoMessage *im;
- const struct GNUNET_HELLO_Message *hello;
- uint16_t ms;
- if (msg == NULL)
- {
- GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO);
- nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
- request_notifications (nc);
- return;
- }
- ms = ntohs (msg->size);
- if ((ms < sizeof (struct InfoMessage)) ||
- (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
- {
- GNUNET_break (0);
- GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO);
- nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
- request_notifications (nc);
- return;
- }
- im = (const struct InfoMessage *) msg;
- hello = NULL;
- if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
- {
- hello = (const struct GNUNET_HELLO_Message *) &im[1];
- if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello))
- {
- GNUNET_break (0);
- GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO);
- nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
- request_notifications (nc);
- return;
- }
- }
-#if DEBUG_PEERINFO
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received information about peer `%s' from peerinfo database\n",
- GNUNET_i2s (&im->peer));
-#endif
- nc->callback (nc->callback_cls, &im->peer, hello, ntohl (im->trust));
- receive_notifications (nc);
+ do_reconnect (nc);
}
/**
- * Read notifications from the client handle and pass them
- * to the callback.
+ * Check that a peerinfo information message is well-formed.
*
- * @param nc our context
+ * @param cls closure
+ * @param im message received
+ * @return #GNUNET_OK if the message is well-formed
*/
-static void
-receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc)
+static int
+check_notification (void *cls,
+ const struct InfoMessage *im)
{
- GNUNET_CLIENT_receive (nc->client,
- &process_notification,
- nc,
- GNUNET_TIME_UNIT_FOREVER_REL);
+ uint16_t ms = ntohs (im->header.size) - sizeof (*im);
+
+ if (ms >= sizeof (struct GNUNET_MessageHeader))
+ {
+ const struct GNUNET_HELLO_Message *hello;
+
+ hello = (const struct GNUNET_HELLO_Message *) &im[1];
+ if (ms != GNUNET_HELLO_size (hello))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+ }
+ if (0 != ms)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK; /* odd... */
}
/**
- * Transmit our init-notify request, start receiving.
+ * Receive a peerinfo information message, process it.
*
- * @param cls closure (our 'struct GNUNET_PEERINFO_NotifyContext')
- * @param size number of bytes available in buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
+ * @param cls closure
+ * @param im message received
*/
-static size_t
-transmit_notify_request (void *cls,
- size_t size,
- void *buf)
+static void
+handle_notification (void *cls,
+ const struct InfoMessage *im)
{
struct GNUNET_PEERINFO_NotifyContext *nc = cls;
- struct GNUNET_MessageHeader hdr;
+ const struct GNUNET_HELLO_Message *hello;
+ uint16_t ms = ntohs (im->header.size) - sizeof (struct InfoMessage);
- nc->init = NULL;
- if (buf == NULL)
- {
- GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO);
- nc->client = GNUNET_CLIENT_connect (nc->sched, "peerinfo", nc->cfg);
- request_notifications (nc);
- return 0;
- }
- GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
- hdr.size = htons (sizeof (struct GNUNET_MessageHeader));
- hdr.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY);
- memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader));
- receive_notifications (nc);
- return sizeof (struct GNUNET_MessageHeader);
+ if (0 == ms)
+ return;
+ hello = (const struct GNUNET_HELLO_Message *) &im[1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received information about peer `%s' from peerinfo database\n",
+ GNUNET_i2s (&im->peer));
+ nc->callback (nc->callback_cls,
+ &im->peer,
+ hello,
+ NULL);
}
/**
- * Send a request to the peerinfo service to start being
- * notified about all changes to peer information.
+ * Task to re-try connecting to peerinfo.
*
- * @param nc our context
+ * @param cls the `struct GNUNET_PEERINFO_NotifyContext *`
*/
static void
-request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc)
+reconnect (void *cls)
{
- GNUNET_assert (NULL == nc->init);
- nc->init =GNUNET_CLIENT_notify_transmit_ready (nc->client,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES,
- &transmit_notify_request,
- nc);
+ GNUNET_MQ_hd_var_size (notification,
+ GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
+ struct InfoMessage);
+ struct GNUNET_PEERINFO_NotifyContext *nc = cls;
+ struct GNUNET_MQ_MessageHandler handlers[] = {
+ make_notification_handler (nc),
+ GNUNET_MQ_handler_end ()
+ };
+ struct GNUNET_MQ_Envelope *env;
+ struct NotifyMessage *nm;
+
+ nc->task = NULL;
+ nc->mq = GNUNET_CLIENT_connecT (nc->cfg,
+ "peerinfo",
+ handlers,
+ &mq_error_handler,
+ nc);
+ if (NULL == nc->mq)
+ return;
+ env = GNUNET_MQ_msg (nm,
+ GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY);
+ nm->include_friend_only = htonl (nc->include_friend_only);
+ GNUNET_MQ_send (nc->mq,
+ env);
}
* changes. Initially calls the given function for all known
* peers and then only signals changes.
*
+ * If @a include_friend_only is set to #GNUNET_YES peerinfo will include HELLO
+ * messages which are intended for friend to friend mode and which do not
+ * have to be gossiped. Otherwise these messages are skipped.
+ *
* @param cfg configuration to use
- * @param sched scheduler to use
+ * @param include_friend_only include HELLO messages for friends only
* @param callback the method to call for each peer
- * @param callback_cls closure for callback
+ * @param callback_cls closure for @a callback
* @return NULL on error
*/
struct GNUNET_PEERINFO_NotifyContext *
GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_SCHEDULER_Handle *sched,
- GNUNET_PEERINFO_Processor callback,
- void *callback_cls)
+ int include_friend_only,
+ GNUNET_PEERINFO_Processor callback,
+ void *callback_cls)
{
struct GNUNET_PEERINFO_NotifyContext *nc;
- struct GNUNET_CLIENT_Connection *client;
-
- client = GNUNET_CLIENT_connect (sched, "peerinfo", cfg);
- if (client == NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Could not connect to `%s' service.\n"), "peerinfo");
- return NULL;
- }
- nc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_NotifyContext));
- nc->sched = sched;
+
+ nc = GNUNET_new (struct GNUNET_PEERINFO_NotifyContext);
nc->cfg = cfg;
- nc->client = client;
nc->callback = callback;
- nc->callback_cls = callback_cls;
- request_notifications (nc);
+ nc->callback_cls = callback_cls;
+ nc->include_friend_only = include_friend_only;
+ reconnect (nc);
+ if (NULL == nc->mq)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Could not connect to PEERINFO service.\n");
+ GNUNET_free (nc);
+ return NULL;
+ }
return nc;
}
void
GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc)
{
- if (NULL != nc->init)
- {
- GNUNET_CLIENT_notify_transmit_ready_cancel (nc->init);
- nc->init = NULL;
- }
- GNUNET_CLIENT_disconnect (nc->client, GNUNET_NO);
+ if (NULL != nc->mq)
+ {
+ GNUNET_MQ_destroy (nc->mq);
+ nc->mq = NULL;
+ }
+ if (NULL != nc->task)
+ {
+ GNUNET_SCHEDULER_cancel (nc->task);
+ nc->task = NULL;
+ }
GNUNET_free (nc);
}