/*
This file is part of GNUnet.
- (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+ (C) 2009-2014 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
*/
/**
- * @file core/core_api_iterate_peers.c
+ * @file core/core_api_monitor_peers.c
* @brief implementation of the peer_iterate function
* @author Christian Grothoff
* @author Nathan Evans
#include "core.h"
-struct GNUNET_CORE_RequestContext
+/**
+ * Handle to a CORE monitoring operation.
+ */
+struct GNUNET_CORE_MonitorHandle
{
+
+ /**
+ * Our configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
/**
* Our connection to the service.
*/
/**
* Function called with the peer.
*/
- GNUNET_CORE_ConnectEventHandler peer_cb;
+ GNUNET_CORE_MonitorCallback peer_cb;
/**
- * Peer to check for.
+ * Closure for @e peer_cb.
*/
- struct GNUNET_PeerIdentity *peer;
-
- /**
- * Closure for peer_cb.
- */
- void *cb_cls;
+ void *peer_cb_cls;
};
/**
- * Receive reply from core service with information about a peer.
+ * Transmits the monitor request to the CORE service.
+ *
+ * Function is called to notify a client about the socket begin ready
+ * to queue more data. @a buf will be NULL and @a size zero if the
+ * socket was closed for writing in the meantime.
+ *
+ * @param cls closure, our `struct GNUNET_CORE_MonitorHandle *`
+ * @param size number of bytes available in @a buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to @a buf
+ */
+static size_t
+transmit_monitor_request (void *cls,
+ size_t size,
+ void *buf);
+
+
+/**
+ * Protocol error, reconnect to CORE service and notify
+ * client.
+ *
+ * @param mh monitoring session to reconnect to CORE
+ */
+static void
+reconnect (struct GNUNET_CORE_MonitorHandle *mh)
+{
+ GNUNET_CLIENT_disconnect (mh->client);
+ /* FIXME: use backoff? */
+ mh->client = GNUNET_CLIENT_connect ("core", mh->cfg);
+ GNUNET_assert (NULL != mh->client);
+ mh->th =
+ GNUNET_CLIENT_notify_transmit_ready (mh->client,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES,
+ &transmit_monitor_request, mh);
+ /* notify callback about reconnect */
+ mh->peer_cb (mh->peer_cb_cls,
+ NULL,
+ GNUNET_CORE_KX_CORE_DISCONNECT,
+ GNUNET_TIME_UNIT_FOREVER_ABS);
+}
+
+
+/**
+ * Receive reply from CORE service with information about a peer.
*
- * @param cls our 'struct GNUNET_CORE_RequestContext *'
+ * @param cls our `struct GNUNET_CORE_MonitorHandle *`
* @param msg NULL on error or last entry
*/
static void
receive_info (void *cls,
- const struct GNUNET_MessageHeader *msg)
+ const struct GNUNET_MessageHeader *msg)
{
- struct GNUNET_CORE_RequestContext *request_context = cls;
- const struct ConnectNotifyMessage *connect_message;
- uint32_t ats_count;
+ struct GNUNET_CORE_MonitorHandle *mh = cls;
+ const struct MonitorNotifyMessage *mon_message;
uint16_t msize;
- /* Handle last message or error case, disconnect and clean up */
- if ( (msg == NULL) ||
- ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END) &&
- (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader))) )
- {
- if (request_context->peer_cb != NULL)
- request_context->peer_cb (request_context->cb_cls,
- NULL, NULL);
- GNUNET_CLIENT_disconnect (request_context->client, GNUNET_NO);
- GNUNET_free (request_context);
- return;
- }
-
+ if (NULL == msg)
+ {
+ reconnect (mh);
+ return;
+ }
msize = ntohs (msg->size);
/* Handle incorrect message type or size, disconnect and clean up */
- if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT) ||
- (msize < sizeof (struct ConnectNotifyMessage)) )
- {
- GNUNET_break (0);
- if (request_context->peer_cb != NULL)
- request_context->peer_cb (request_context->cb_cls,
- NULL, NULL);
- GNUNET_CLIENT_disconnect (request_context->client, GNUNET_NO);
- GNUNET_free (request_context);
- return;
- }
- connect_message = (const struct ConnectNotifyMessage *) msg;
- ats_count = ntohl (connect_message->ats_count);
- if ( (msize != sizeof (struct ConnectNotifyMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)) ||
- (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR != ntohl ((&connect_message->ats)[ats_count].type)) )
- {
- GNUNET_break (0);
- if (request_context->peer_cb != NULL)
- request_context->peer_cb (request_context->cb_cls,
- NULL, NULL);
- GNUNET_CLIENT_disconnect (request_context->client, GNUNET_NO);
- GNUNET_free (request_context);
- return;
- }
- /* Normal case */
- if (request_context->peer_cb != NULL)
- request_context->peer_cb (request_context->cb_cls,
- &connect_message->peer,
- &connect_message->ats);
- GNUNET_CLIENT_receive(request_context->client,
- &receive_info,
- request_context,
- GNUNET_TIME_UNIT_FOREVER_REL);
+ if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY) ||
+ (sizeof (struct MonitorNotifyMessage) != msize))
+ {
+ GNUNET_break (0);
+ reconnect (mh);
+ return;
+ }
+ mon_message = (const struct MonitorNotifyMessage *) msg;
+ GNUNET_CLIENT_receive (mh->client,
+ &receive_info, mh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ mh->peer_cb (mh->peer_cb_cls,
+ &mon_message->peer,
+ (enum GNUNET_CORE_KxState) ntohl (mon_message->state),
+ GNUNET_TIME_absolute_ntoh (mon_message->timeout));
}
+
/**
- * Function called to notify a client about the socket
- * begin ready to queue more data. "buf" will be
- * NULL and "size" zero if the socket was closed for
- * writing in the meantime.
+ * Transmits the monitor request to the CORE service.
+ *
+ * Function is called to notify a client about the socket begin ready
+ * to queue more data. @a buf will be NULL and @a size zero if the
+ * socket was closed for writing in the meantime.
*
- * @param cls closure
- * @param size number of bytes available in buf
+ * @param cls closure, our `struct GNUNET_CORE_MonitorHandle *`
+ * @param size number of bytes available in @a buf
* @param buf where the callee should write the message
- * @return number of bytes written to buf
+ * @return number of bytes written to @a buf
*/
static size_t
-transmit_request(void *cls,
- size_t size, void *buf)
+transmit_monitor_request (void *cls,
+ size_t size,
+ void *buf)
{
+ struct GNUNET_CORE_MonitorHandle *mh = cls;
struct GNUNET_MessageHeader *msg;
- struct GNUNET_PeerIdentity *peer = cls;
int msize;
- if (peer == NULL)
- msize = sizeof(struct GNUNET_MessageHeader);
- else
- msize = sizeof(struct GNUNET_MessageHeader) + sizeof(struct GNUNET_PeerIdentity);
-
- if ((size < msize) || (buf == NULL))
+ msize = sizeof (struct GNUNET_MessageHeader);
+ if ((size < msize) || (NULL == buf))
+ {
+ reconnect (mh);
return 0;
-
- msg = (struct GNUNET_MessageHeader *)buf;
+ }
+ msg = (struct GNUNET_MessageHeader *) buf;
msg->size = htons (msize);
- msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS);
- if (peer != NULL)
- memcpy(&msg[1], peer, sizeof(struct GNUNET_PeerIdentity));
-
+ msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS);
+ GNUNET_CLIENT_receive (mh->client,
+ &receive_info, mh,
+ GNUNET_TIME_UNIT_FOREVER_REL);
return msize;
}
+
/**
- * Iterate over all currently connected peers.
- * Calls peer_cb with each connected peer, and then
- * once with NULL to indicate that all peers have
- * been handled.
+ * Monitor connectivity and KX status of all peers known to CORE.
+ * Calls @a peer_cb with the current status for each connected peer,
+ * and then once with NULL to indicate that all peers that are
+ * currently active have been handled. After that, the iteration
+ * continues until it is cancelled. Normal users of the CORE API are
+ * not expected to use this function. It is different in that it
+ * truly lists all connections (including those where the KX is in
+ * progress), not just those relevant to the application. This
+ * function is used by special applications for diagnostics.
*
- * @param cfg configuration to use
- * @param peer the specific peer to check for
+ * @param cfg configuration handle
* @param peer_cb function to call with the peer information
- * @param cb_cls closure for peer_cb
- *
- * @return GNUNET_OK if iterating, GNUNET_SYSERR on error
+ * @param peer_cb_cls closure for @a peer_cb
+ * @return NULL on error
*/
-int
-GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_PeerIdentity *peer,
- GNUNET_CORE_ConnectEventHandler peer_cb,
- void *cb_cls)
+struct GNUNET_CORE_MonitorHandle *
+GNUNET_CORE_monitor_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_CORE_MonitorCallback peer_cb,
+ void *peer_cb_cls)
{
- struct GNUNET_CORE_RequestContext *request_context;
+ struct GNUNET_CORE_MonitorHandle *mh;
struct GNUNET_CLIENT_Connection *client;
+ GNUNET_assert (NULL != peer_cb);
client = GNUNET_CLIENT_connect ("core", cfg);
- if (client == NULL)
- return GNUNET_SYSERR;
- GNUNET_assert(peer != NULL);
- request_context = GNUNET_malloc (sizeof (struct GNUNET_CORE_RequestContext));
- request_context->client = client;
- request_context->peer_cb = peer_cb;
- request_context->cb_cls = cb_cls;
- request_context->peer = peer;
-
- request_context->th = GNUNET_CLIENT_notify_transmit_ready(client,
- sizeof(struct GNUNET_MessageHeader) + sizeof(struct GNUNET_PeerIdentity),
- GNUNET_TIME_relative_get_forever(),
- GNUNET_YES,
- &transmit_request,
- peer);
-
- GNUNET_CLIENT_receive(client, &receive_info, request_context, GNUNET_TIME_relative_get_forever());
- return GNUNET_OK;
+ if (NULL == client)
+ return NULL;
+ mh = GNUNET_new (struct GNUNET_CORE_MonitorHandle);
+ mh->cfg = cfg;
+ mh->client = client;
+ mh->peer_cb = peer_cb;
+ mh->peer_cb_cls = peer_cb_cls;
+ mh->th =
+ GNUNET_CLIENT_notify_transmit_ready (client,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES,
+ &transmit_monitor_request, mh);
+ return mh;
}
+
/**
- * Iterate over all currently connected peers.
- * Calls peer_cb with each connected peer, and then
- * once with NULL to indicate that all peers have
- * been handled.
- *
- * @param cfg configuration to use
- * @param peer_cb function to call with the peer information
- * @param cb_cls closure for peer_cb
+ * Stop monitoring CORE activity.
*
- * @return GNUNET_OK if iterating, GNUNET_SYSERR on error
+ * @param mh monitor to stop
*/
-int
-GNUNET_CORE_iterate_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
- GNUNET_CORE_ConnectEventHandler peer_cb,
- void *cb_cls)
+void
+GNUNET_CORE_monitor_stop (struct GNUNET_CORE_MonitorHandle *mh)
{
- struct GNUNET_CORE_RequestContext *request_context;
- struct GNUNET_CLIENT_Connection *client;
-
- client = GNUNET_CLIENT_connect ("core", cfg);
- if (client == NULL)
- return GNUNET_SYSERR;
- request_context = GNUNET_malloc (sizeof (struct GNUNET_CORE_RequestContext));
- request_context->client = client;
- request_context->peer_cb = peer_cb;
- request_context->cb_cls = cb_cls;
-
- request_context->th = GNUNET_CLIENT_notify_transmit_ready(client,
- sizeof(struct GNUNET_MessageHeader),
- GNUNET_TIME_relative_get_forever(),
- GNUNET_YES,
- &transmit_request,
- NULL);
-
- GNUNET_CLIENT_receive(client, &receive_info, request_context, GNUNET_TIME_relative_get_forever());
- return GNUNET_OK;
+ if (NULL != mh->th)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (mh->th);
+ mh->th = NULL;
+ }
+ if (NULL != mh->client)
+ {
+ GNUNET_CLIENT_disconnect (mh->client);
+ mh->client = NULL;
+ }
+ GNUNET_free (mh);
}
-/* end of core_api_iterate_peers.c */
+
+/* end of core_api_monitor_peers.c */