gnunet_service_core_SOURCES = \
gnunet-service-core.c gnunet-service-core.h \
- gnunet-service-core_clients.c gnunet-service-core_clients.h \
gnunet-service-core_kx.c gnunet-service-core_kx.h \
gnunet-service-core_sessions.c gnunet-service-core_sessions.h \
gnunet-service-core_typemap.c gnunet-service-core_typemap.h
uint16_t et;
GNUNET_break (GNUNET_NO == h->currently_down);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received inbound message from `%s'.\n",
- GNUNET_i2s (&ntm->peer));
em = (const struct GNUNET_MessageHeader *) &ntm[1];
et = ntohs (em->type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received inbound message of type %d from `%s'.\n",
+ (int) et,
+ GNUNET_i2s (&ntm->peer));
for (unsigned int hpos = 0; NULL != h->handlers[hpos].callback; hpos++)
{
const struct GNUNET_CORE_MessageHandler *mh;
/*
This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2011 GNUnet e.V.
+ Copyright (C) 2009, 2010, 2011, 2016 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
#include <gcrypt.h>
#include "gnunet_util_lib.h"
#include "gnunet-service-core.h"
-#include "gnunet-service-core_clients.h"
#include "gnunet-service-core_kx.h"
#include "gnunet-service-core_sessions.h"
#include "gnunet-service-core_typemap.h"
+/**
+ * How many messages do we queue up at most for optional
+ * notifications to a client? (this can cause notifications
+ * about outgoing messages to be dropped).
+ */
+#define MAX_NOTIFY_QUEUE 1024
+
+
+/**
+ * Data structure for each client connected to the CORE service.
+ */
+struct GSC_Client
+{
+ /**
+ * Clients are kept in a linked list.
+ */
+ struct GSC_Client *next;
+
+ /**
+ * Clients are kept in a linked list.
+ */
+ struct GSC_Client *prev;
+
+ /**
+ * Handle for the client with the server API.
+ */
+ struct GNUNET_SERVICE_Client *client;
+
+ /**
+ * Message queue to talk to @e client.
+ */
+ struct GNUNET_MQ_Handle *mq;
+
+ /**
+ * Array of the types of messages this peer cares
+ * about (with @e tcnt entries). Allocated as part
+ * of this client struct, do not free!
+ */
+ uint16_t *types;
+
+ /**
+ * Map of peer identities to active transmission requests of this
+ * client to the peer (of type `struct GSC_ClientActiveRequest`).
+ */
+ struct GNUNET_CONTAINER_MultiPeerMap *requests;
+
+ /**
+ * Map containing all peers that this client knows we're connected to.
+ */
+ struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
+
+ /**
+ * Options for messages this client cares about,
+ * see GNUNET_CORE_OPTION_ values.
+ */
+ uint32_t options;
+
+ /**
+ * Number of types of incoming messages this client
+ * specifically cares about. Size of the @e types array.
+ */
+ unsigned int tcnt;
+
+};
+
/**
* Our identity.
struct GNUNET_STATISTICS_Handle *GSC_stats;
/**
- * Handle to the server of the core service.
+ * Big "or" of all client options.
+ */
+static uint32_t all_client_options;
+
+/**
+ * Head of linked list of our clients.
+ */
+static struct GSC_Client *client_head;
+
+/**
+ * Tail of linked list of our clients.
+ */
+static struct GSC_Client *client_tail;
+
+
+/**
+ * Test if the client is interested in messages of the given type.
+ *
+ * @param type message type
+ * @param c client to test
+ * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
+ */
+static int
+type_match (uint16_t type,
+ struct GSC_Client *c)
+{
+ if ( (0 == c->tcnt) &&
+ (0 != c->options) )
+ return GNUNET_YES; /* peer without handlers and inbound/outbond
+ callbacks matches ALL */
+ if (NULL == c->types)
+ return GNUNET_NO;
+ for (unsigned int i = 0; i < c->tcnt; i++)
+ if (type == c->types[i])
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
+ *
+ * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
+ * @param im the `struct InitMessage`
+ * @return #GNUNET_OK if @a im is well-formed
*/
-static struct GNUNET_SERVER_Handle *GSC_server;
+static int
+check_client_init (void *cls,
+ const struct InitMessage *im)
+{
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
+ *
+ * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
+ * @param im the `struct InitMessage`
+ */
+static void
+handle_client_init (void *cls,
+ const struct InitMessage *im)
+{
+ struct GSC_Client *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct InitReplyMessage *irm;
+ uint16_t msize;
+ const uint16_t *types;
+
+ /* check that we don't have an entry already */
+ msize = ntohs (im->header.size) - sizeof (struct InitMessage);
+ types = (const uint16_t *) &im[1];
+ c->tcnt = msize / sizeof (uint16_t);
+ c->options = ntohl (im->options);
+ all_client_options |= c->options;
+ c->types = GNUNET_malloc (msize);
+ c->connectmap = GNUNET_CONTAINER_multipeermap_create (16,
+ GNUNET_NO);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_put (c->connectmap,
+ &GSC_my_identity,
+ NULL,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ for (unsigned int i = 0; i < c->tcnt; i++)
+ c->types[i] = ntohs (types[i]);
+ GSC_TYPEMAP_add (c->types,
+ c->tcnt);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client connecting to core service is interested in %u message types\n",
+ (unsigned int) c->tcnt);
+ /* send init reply message */
+ env = GNUNET_MQ_msg (irm,
+ GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
+ irm->reserved = htonl (0);
+ irm->my_identity = GSC_my_identity;
+ GNUNET_MQ_send (c->mq,
+ env);
+ GSC_SESSIONS_notify_client_about_sessions (c);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * We will never be ready to transmit the given message in (disconnect
+ * or invalid request). Frees resources associated with @a car. We
+ * don't explicitly tell the client, he'll learn with the disconnect
+ * (or violated the protocol).
+ *
+ * @param car request that now permanently failed; the
+ * responsibility for the handle is now returned
+ * to CLIENTS (SESSIONS is done with it).
+ * @param drop_client #GNUNET_YES if the client violated the protocol
+ * and we should thus drop the connection
+ */
+void
+GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
+ int drop_client)
+{
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (car->
+ client_handle->requests,
+ &car->target,
+ car));
+ if (GNUNET_YES == drop_client)
+ GNUNET_SERVICE_client_drop (car->client_handle->client);
+ GNUNET_free (car);
+}
+
+
+/**
+ * Tell a client that we are ready to receive the message.
+ *
+ * @param car request that is now ready; the responsibility
+ * for the handle remains shared between CLIENTS
+ * and SESSIONS after this call.
+ */
+void
+GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
+{
+ struct GSC_Client *c;
+ struct GNUNET_MQ_Envelope *env;
+ struct SendMessageReady *smr;
+ struct GNUNET_TIME_Relative delay;
+ struct GNUNET_TIME_Relative left;
+
+ c = car->client_handle;
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
+ &car->target))
+ {
+ /* connection has gone down since, drop request */
+ GNUNET_assert (0 !=
+ memcmp (&car->target,
+ &GSC_my_identity,
+ sizeof (struct GNUNET_PeerIdentity)));
+ GSC_SESSIONS_dequeue_request (car);
+ GSC_CLIENTS_reject_request (car,
+ GNUNET_NO);
+ return;
+ }
+ delay = GNUNET_TIME_absolute_get_duration (car->received_time);
+ left = GNUNET_TIME_absolute_get_duration (car->deadline);
+ if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES),
+ GNUNET_i2s (&car->target),
+ (0 == left.rel_value_us)
+ ? " (past deadline)"
+ : "",
+ car->priority);
+ env = GNUNET_MQ_msg (smr,
+ GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
+ smr->size = htons (car->msize);
+ smr->smr_id = car->smr_id;
+ smr->peer = car->target;
+ GNUNET_MQ_send (c->mq,
+ env);
+}
+
+
+/**
+ * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
+ *
+ * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
+ * @param req the `struct SendMessageRequest`
+ */
+static void
+handle_client_send_request (void *cls,
+ const struct SendMessageRequest *req)
+{
+ struct GSC_Client *c = cls;
+ struct GSC_ClientActiveRequest *car;
+ int is_loopback;
+
+ if (NULL == c->requests)
+ c->requests = GNUNET_CONTAINER_multipeermap_create (16,
+ GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client asked for transmission to `%s'\n",
+ GNUNET_i2s (&req->peer));
+ is_loopback =
+ (0 ==
+ memcmp (&req->peer,
+ &GSC_my_identity,
+ sizeof (struct GNUNET_PeerIdentity)));
+ if ((! is_loopback) &&
+ (GNUNET_YES !=
+ GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
+ &req->peer)))
+ {
+ /* neighbour must have disconnected since request was issued,
+ * ignore (client will realize it once it processes the
+ * disconnect notification) */
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop
+ ("# send requests dropped (disconnected)"), 1,
+ GNUNET_NO);
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+
+ car = GNUNET_CONTAINER_multipeermap_get (c->requests,
+ &req->peer);
+ if (NULL == car)
+ {
+ /* create new entry */
+ car = GNUNET_new (struct GSC_ClientActiveRequest);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multipeermap_put (c->requests,
+ &req->peer,
+ car,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+ car->client_handle = c;
+ }
+ else
+ {
+ /* dequeue and recycle memory from pending request, there can only
+ be at most one per client and peer */
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop ("# dequeuing CAR (duplicate request)"),
+ 1,
+ GNUNET_NO);
+ GSC_SESSIONS_dequeue_request (car);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission request to `%s' was a duplicate!\n",
+ GNUNET_i2s (&req->peer));
+ }
+ car->target = req->peer;
+ car->received_time = GNUNET_TIME_absolute_get ();
+ car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
+ car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
+ car->msize = ntohs (req->size);
+ car->smr_id = req->smr_id;
+ car->was_solicited = GNUNET_NO;
+ GNUNET_SERVICE_client_continue (c->client);
+ if (is_loopback)
+ {
+ /* loopback, satisfy immediately */
+ GSC_CLIENTS_solicit_request (car);
+ return;
+ }
+ GSC_SESSIONS_queue_request (car);
+}
+
+
+/**
+ * Closure for the #client_tokenizer_callback().
+ */
+struct TokenizerContext
+{
+
+ /**
+ * Active request handle for the message.
+ */
+ struct GSC_ClientActiveRequest *car;
+
+ /**
+ * How important is this message.
+ */
+ enum GNUNET_CORE_Priority priority;
+
+ /**
+ * Is corking allowed (set only once we have the real message).
+ */
+ int cork;
+
+};
+
+
+/**
+ * Functions with this signature are called whenever a complete
+ * message is received by the tokenizer. Used by
+ * #handle_client_send() for dispatching messages from clients to
+ * either the SESSION subsystem or other CLIENT (for loopback).
+ *
+ * @param cls reservation request (`struct TokenizerContext`)
+ * @param message the actual message
+ */
+static int
+tokenized_cb (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct TokenizerContext *tc = cls;
+ struct GSC_ClientActiveRequest *car = tc->car;
+ char buf[92];
+
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ gettext_noop ("# bytes of messages of type %u received"),
+ (unsigned int) ntohs (message->type));
+ GNUNET_STATISTICS_update (GSC_stats,
+ buf,
+ ntohs (message->size),
+ GNUNET_NO);
+ if (0 ==
+ memcmp (&car->target,
+ &GSC_my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Delivering message of type %u to myself\n",
+ ntohs (message->type));
+ GSC_CLIENTS_deliver_message (&GSC_my_identity,
+ message,
+ ntohs (message->size),
+ GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
+ GSC_CLIENTS_deliver_message (&GSC_my_identity,
+ message,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
+ GSC_CLIENTS_deliver_message (&GSC_my_identity,
+ message,
+ ntohs (message->size),
+ GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
+ GSC_CLIENTS_deliver_message (&GSC_my_identity,
+ message,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Delivering message of type %u and size %u to %s\n",
+ ntohs (message->type),
+ ntohs (message->size),
+ GNUNET_i2s (&car->target));
+ GSC_CLIENTS_deliver_message (&car->target,
+ message,
+ ntohs (message->size),
+ GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
+ GSC_CLIENTS_deliver_message (&car->target,
+ message,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
+ GSC_SESSIONS_transmit (car,
+ message,
+ tc->cork,
+ tc->priority);
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
+ *
+ * @param cls the `struct GSC_Client`
+ * @param sm the `struct SendMessage`
+ * @return #GNUNET_OK if @a sm is well-formed
+ */
+static int
+check_client_send (void *cls,
+ const struct SendMessage *sm)
+{
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
+ *
+ * @param cls the `struct GSC_Client`
+ * @param sm the `struct SendMessage`
+ */
+static void
+handle_client_send (void *cls,
+ const struct SendMessage *sm)
+{
+ struct GSC_Client *c = cls;
+ struct TokenizerContext tc;
+ uint16_t msize;
+ struct GNUNET_TIME_Relative delay;
+ struct GNUNET_MessageStreamTokenizer *mst;
+
+ msize = ntohs (sm->header.size) - sizeof (struct SendMessage);
+ GNUNET_break (0 == ntohl (sm->reserved));
+ tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
+ &sm->peer);
+ if (NULL == tc.car)
+ {
+ /* Must have been that we first approved the request, then got disconnected
+ * (which triggered removal of the 'car') and now the client gives us a message
+ * just *before* the client learns about the disconnect. Theoretically, we
+ * might also now be *again* connected. So this can happen (but should be
+ * rare). If it does happen, the message is discarded. */
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop ("# messages discarded (session disconnected)"),
+ 1,
+ GNUNET_NO);
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+ delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
+ tc.cork = ntohl (sm->cork);
+ tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
+ if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Client waited %s for transmission of %u bytes to `%s'%s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES),
+ msize,
+ GNUNET_i2s (&sm->peer),
+ tc.cork ? " (cork)" : " (uncorked)");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client waited %s for transmission of %u bytes to `%s'%s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES),
+ msize,
+ GNUNET_i2s (&sm->peer),
+ tc.cork ? " (cork)" : " (uncorked)");
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (c->requests,
+ &sm->peer,
+ tc.car));
+ mst = GNUNET_MST_create (&tokenized_cb,
+ &tc);
+ GNUNET_MST_from_buffer (mst,
+ (const char *) &sm[1],
+ msize,
+ GNUNET_YES,
+ GNUNET_NO);
+ GNUNET_MST_destroy (mst);
+ GSC_SESSIONS_dequeue_request (tc.car);
+ GNUNET_free (tc.car);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Free client request records.
+ *
+ * @param cls NULL
+ * @param key identity of peer for which this is an active request
+ * @param value the `struct GSC_ClientActiveRequest` to free
+ * @return #GNUNET_YES (continue iteration)
+ */
+static int
+destroy_active_client_request (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct GSC_ClientActiveRequest *car = value;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (car->
+ client_handle->requests,
+ &car->target,
+ car));
+ GSC_SESSIONS_dequeue_request (car);
+ GNUNET_free (car);
+ return GNUNET_YES;
+}
+
+
+/**
+ * A client connected, set up.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param mq message queue to talk to @a client
+ * @return our client handle
+ */
+static void *
+client_connect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ struct GNUNET_MQ_Handle *mq)
+{
+ struct GSC_Client *c;
+
+ c = GNUNET_new (struct GSC_Client);
+ c->client = client;
+ c->mq = mq;
+ GNUNET_CONTAINER_DLL_insert (client_head,
+ client_tail,
+ c);
+ return c;
+}
+
+
+/**
+ * A client disconnected, clean up.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param app_ctx our `struct GST_Client` for @a client
+ */
+static void
+client_disconnect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ void *app_ctx)
+{
+ struct GSC_Client *c = app_ctx;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client %p has disconnected from core service.\n",
+ client);
+ GNUNET_CONTAINER_DLL_remove (client_head,
+ client_tail,
+ c);
+ if (NULL != c->requests)
+ {
+ GNUNET_CONTAINER_multipeermap_iterate (c->requests,
+ &destroy_active_client_request,
+ NULL);
+ GNUNET_CONTAINER_multipeermap_destroy (c->requests);
+ }
+ if (NULL != c->connectmap)
+ {
+ GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
+ c->connectmap = NULL;
+ }
+ if (NULL != c->types)
+ {
+ GSC_TYPEMAP_remove (c->types,
+ c->tcnt);
+ GNUNET_free (c->types);
+ }
+ GNUNET_free (c);
+
+ /* recalculate 'all_client_options' */
+ all_client_options = 0;
+ for (c = client_head; NULL != c ; c = c->next)
+ all_client_options |= c->options;
+}
+
+
+/**
+ * Notify a particular client about a change to existing connection to
+ * one of our neighbours (check if the client is interested). Called
+ * from #GSC_SESSIONS_notify_client_about_sessions().
+ *
+ * @param client client to notify
+ * @param neighbour identity of the neighbour that changed status
+ * @param tmap_old previous type map for the neighbour, NULL for connect
+ * @param tmap_new updated type map for the neighbour, NULL for disconnect
+ */
+void
+GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
+ const struct GNUNET_PeerIdentity *neighbour,
+ const struct GSC_TypeMap *tmap_old,
+ const struct GSC_TypeMap *tmap_new)
+{
+ struct GNUNET_MQ_Envelope *env;
+ int old_match;
+ int new_match;
+
+ old_match = GSC_TYPEMAP_test_match (tmap_old,
+ client->types,
+ client->tcnt);
+ new_match = GSC_TYPEMAP_test_match (tmap_new,
+ client->types,
+ client->tcnt);
+ if (old_match == new_match)
+ {
+ GNUNET_assert (old_match ==
+ GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
+ neighbour));
+ return; /* no change */
+ }
+ if (GNUNET_NO == old_match)
+ {
+ struct ConnectNotifyMessage *cnm;
+
+ /* send connect */
+ GNUNET_assert (GNUNET_NO ==
+ GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
+ neighbour));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_put (client->connectmap,
+ neighbour,
+ NULL,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ env = GNUNET_MQ_msg (cnm,
+ GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
+ cnm->reserved = htonl (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending NOTIFY_CONNECT message to client.\n");
+ cnm->peer = *neighbour;
+ GNUNET_MQ_send (client->mq,
+ env);
+ }
+ else
+ {
+ struct DisconnectNotifyMessage *dcm;
+
+ /* send disconnect */
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
+ neighbour));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
+ neighbour,
+ NULL));
+ env = GNUNET_MQ_msg (dcm,
+ GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
+ dcm->reserved = htonl (0);
+ dcm->peer = *neighbour;
+ GNUNET_MQ_send (client->mq,
+ env);
+ }
+}
+
+
+/**
+ * Notify all clients about a change to existing session.
+ * Called from SESSIONS whenever there is a change in sessions
+ * or types processed by the respective peer.
+ *
+ * @param neighbour identity of the neighbour that changed status
+ * @param tmap_old previous type map for the neighbour, NULL for connect
+ * @param tmap_new updated type map for the neighbour, NULL for disconnect
+ */
+void
+GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
+ const struct GSC_TypeMap *tmap_old,
+ const struct GSC_TypeMap *tmap_new)
+{
+ struct GSC_Client *c;
+
+ for (c = client_head; NULL != c; c = c->next)
+ GSC_CLIENTS_notify_client_about_neighbour (c,
+ neighbour,
+ tmap_old,
+ tmap_new);
+}
+
+
+/**
+ * Deliver P2P message to interested clients. Caller must have checked
+ * that the sending peer actually lists the given message type as one
+ * of its types.
+ *
+ * @param sender peer who sent us the message
+ * @param msg the message
+ * @param msize number of bytes to transmit
+ * @param options options for checking which clients should
+ * receive the message
+ */
+void
+GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *msg,
+ uint16_t msize,
+ uint32_t options)
+{
+ size_t size = msize + sizeof (struct NotifyTrafficMessage);
+
+ if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (! ( (0 != (all_client_options & options)) ||
+ (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
+ return; /* no client cares about this message notification */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core service passes message from `%s' of type %u to client.\n",
+ GNUNET_i2s (sender),
+ (unsigned int) ntohs (msg->type));
+ GSC_SESSIONS_add_to_typemap (sender,
+ ntohs (msg->type));
+
+ for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
+ {
+ struct GNUNET_MQ_Envelope *env;
+ struct NotifyTrafficMessage *ntm;
+ uint16_t mtype;
+ int tm;
+
+ tm = type_match (ntohs (msg->type),
+ c);
+ if (! ( (0 != (c->options & options)) ||
+ ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
+ (GNUNET_YES == tm) ) ) )
+ continue; /* neither options nor type match permit the message */
+ if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
+ ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
+ (GNUNET_YES == tm) ) )
+ continue;
+ if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
+ (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
+ continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending %u message with %u bytes to client interested in messages of type %u.\n",
+ options,
+ ntohs (msg->size),
+ (unsigned int) ntohs (msg->type));
+
+ if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
+ mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
+ else
+ mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
+ env = GNUNET_MQ_msg_extra (ntm,
+ msize,
+ mtype);
+ ntm->peer = *sender;
+ GNUNET_memcpy (&ntm[1],
+ msg,
+ msize);
+
+ GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
+ (GNUNET_YES != tm) ||
+ (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
+ sender)) );
+ GNUNET_MQ_send (c->mq,
+ env);
+ }
+}
/**
static void
shutdown_task (void *cls)
{
+ struct GSC_Client *c;
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service shutting down.\n");
- GSC_CLIENTS_done ();
+ while (NULL != (c = client_head))
+ GNUNET_SERVICE_client_drop (c->client);
GSC_SESSIONS_done ();
GSC_KX_done ();
GSC_TYPEMAP_done ();
}
+/**
+ * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
+ * request type, the client does not have to have transmitted an INIT
+ * request. All current peers are returned, regardless of which
+ * message types they accept.
+ *
+ * @param cls client sending the iteration request
+ * @param message iteration request message
+ */
+static void
+handle_client_monitor_peers (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GSC_Client *c = cls;
+
+ GNUNET_SERVICE_client_continue (c->client);
+ GSC_KX_handle_client_monitor_peers (c->mq);
+}
+
+
/**
* Initiate core service.
*
* @param cls closure
- * @param server the initialized server
* @param c configuration to use
+ * @param service the initialized service
*/
static void
run (void *cls,
- struct GNUNET_SERVER_Handle *server,
- const struct GNUNET_CONFIGURATION_Handle *c)
+ const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_SERVICE_Handle *service)
{
struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
char *keyfile;
GSC_cfg = c;
- GSC_server = server;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
"PEER",
GSC_cfg);
GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
NULL);
- GNUNET_SERVER_suspend (server);
+ GNUNET_SERVICE_suspend (service);
GSC_TYPEMAP_init ();
pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
GNUNET_free (keyfile);
GNUNET_assert (NULL != pk);
- if (GNUNET_OK != GSC_KX_init (pk,
- server))
+ if (GNUNET_OK != GSC_KX_init (pk))
{
GNUNET_SCHEDULER_shutdown ();
return;
}
GSC_SESSIONS_init ();
- GSC_CLIENTS_init (GSC_server);
- GNUNET_SERVER_resume (GSC_server);
+ GNUNET_SERVICE_resume (service);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Core service of `%s' ready.\n"),
GNUNET_i2s (&GSC_my_identity));
/**
- * The main function for the transport service.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
+ * Define "main" method using service macro.
*/
-int
-main (int argc, char *const *argv)
-{
- return (GNUNET_OK ==
- GNUNET_SERVICE_run (argc, argv, "core",
- GNUNET_SERVICE_OPTION_NONE,
- &run, NULL)) ? 0 : 1;
-}
+GNUNET_SERVICE_MAIN
+("core",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_var_size (client_init,
+ GNUNET_MESSAGE_TYPE_CORE_INIT,
+ struct InitMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (client_monitor_peers,
+ GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (client_send_request,
+ GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
+ struct SendMessageRequest,
+ NULL),
+ GNUNET_MQ_hd_var_size (client_send,
+ GNUNET_MESSAGE_TYPE_CORE_SEND,
+ struct SendMessage,
+ NULL),
+ GNUNET_MQ_handler_end ());
+
/* end of gnunet-service-core.c */
#include "gnunet_statistics_service.h"
#include "gnunet_core_service.h"
#include "core.h"
+#include "gnunet-service-core_typemap.h"
+
/**
* Opaque handle to a client.
};
+/**
+ * Tell a client that we are ready to receive the message.
+ *
+ * @param car request that is now ready; the responsibility
+ * for the handle remains shared between CLIENTS
+ * and SESSIONS after this call.
+ */
+void
+GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car);
+
+
+/**
+ * We will never be ready to transmit the given message in (disconnect
+ * or invalid request). Frees resources associated with @a car. We
+ * don't explicitly tell the client, he'll learn with the disconnect
+ * (or violated the protocol).
+ *
+ * @param car request that now permanently failed; the
+ * responsibility for the handle is now returned
+ * to CLIENTS (SESSIONS is done with it).
+ * @param drop_client #GNUNET_YES if the client violated the protocol
+ * and we should thus drop the connection
+ */
+void
+GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
+ int drop_client);
+
+
+/**
+ * Notify a particular client about a change to existing connection to
+ * one of our neighbours (check if the client is interested). Called
+ * from #GSC_SESSIONS_notify_client_about_sessions().
+ *
+ * @param client client to notify
+ * @param neighbour identity of the neighbour that changed status
+ * @param tmap_old previous type map for the neighbour, NULL for connect
+ * @param tmap_new updated type map for the neighbour, NULL for disconnect
+ */
+void
+GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
+ const struct GNUNET_PeerIdentity *neighbour,
+ const struct GSC_TypeMap *tmap_old,
+ const struct GSC_TypeMap *tmap_new);
+
+
+/**
+ * Deliver P2P message to interested clients. Caller must have checked
+ * that the sending peer actually lists the given message type as one
+ * of its types.
+ *
+ * @param sender peer who sent us the message
+ * @param msg the message
+ * @param msize number of bytes to transmit
+ * @param options options for checking which clients should
+ * receive the message
+ */
+void
+GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *msg,
+ uint16_t msize,
+ uint32_t options);
+
+
+/**
+ * Notify all clients about a change to existing session.
+ * Called from SESSIONS whenever there is a change in sessions
+ * or types processed by the respective peer.
+ *
+ * @param neighbour identity of the neighbour that changed status
+ * @param tmap_old previous type map for the neighbour, NULL for connect
+ * @param tmap_new updated type map for the neighbour, NULL for disconnect
+ */
+void
+GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
+ const struct GSC_TypeMap *tmap_old,
+ const struct GSC_TypeMap *tmap_new);
+
+
/**
* Our configuration.
*/
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2011 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, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file core/gnunet-service-core_clients.c
- * @brief code for managing interactions with clients of core service
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet_transport_service.h"
-#include "gnunet-service-core.h"
-#include "gnunet-service-core_clients.h"
-#include "gnunet-service-core_sessions.h"
-#include "gnunet-service-core_typemap.h"
-#include "core.h"
-
-
-/**
- * How many messages do we queue up at most for optional
- * notifications to a client? (this can cause notifications
- * about outgoing messages to be dropped).
- */
-#define MAX_NOTIFY_QUEUE 1024
-
-
-/**
- * Data structure for each client connected to the CORE service.
- */
-struct GSC_Client
-{
- /**
- * Clients are kept in a linked list.
- */
- struct GSC_Client *next;
-
- /**
- * Clients are kept in a linked list.
- */
- struct GSC_Client *prev;
-
- /**
- * Handle for the client with the server API.
- */
- struct GNUNET_SERVER_Client *client_handle;
-
- /**
- * Array of the types of messages this peer cares
- * about (with @e tcnt entries). Allocated as part
- * of this client struct, do not free!
- */
- const uint16_t *types;
-
- /**
- * Map of peer identities to active transmission requests of this
- * client to the peer (of type `struct GSC_ClientActiveRequest`).
- */
- struct GNUNET_CONTAINER_MultiPeerMap *requests;
-
- /**
- * Map containing all peers that this client knows we're connected to.
- */
- struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
-
- /**
- * Options for messages this client cares about,
- * see GNUNET_CORE_OPTION_ values.
- */
- uint32_t options;
-
- /**
- * Number of types of incoming messages this client
- * specifically cares about. Size of the @e types array.
- */
- unsigned int tcnt;
-
-};
-
-
-/**
- * Big "or" of all client options.
- */
-static uint32_t all_client_options;
-
-/**
- * Head of linked list of our clients.
- */
-static struct GSC_Client *client_head;
-
-/**
- * Tail of linked list of our clients.
- */
-static struct GSC_Client *client_tail;
-
-/**
- * Context for notifications we need to send to our clients.
- */
-static struct GNUNET_SERVER_NotificationContext *notifier;
-
-/**
- * Tokenizer for messages received from clients.
- */
-static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst;
-
-
-/**
- * Lookup our client struct given the server's client handle.
- *
- * @param client server client handle to look up
- * @return our client handle for the client
- */
-static struct GSC_Client *
-find_client (struct GNUNET_SERVER_Client *client)
-{
- struct GSC_Client *c;
-
- c = client_head;
- while ((c != NULL) && (c->client_handle != client))
- c = c->next;
- return c;
-}
-
-
-/**
- * Send a message to one of our clients.
- *
- * @param client target for the message
- * @param msg message to transmit
- * @param can_drop could this message be dropped if the
- * client's queue is getting too large?
- */
-static void
-send_to_client (struct GSC_Client *client,
- const struct GNUNET_MessageHeader *msg,
- int can_drop)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Preparing to send %u bytes of message of type %u to client.\n",
- (unsigned int) ntohs (msg->size),
- (unsigned int) ntohs (msg->type));
- GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
- msg, can_drop);
-}
-
-
-/**
- * Send a message to one of our clients.
- *
- * @param client target for the message
- * @param msg message to transmit
- * @param can_drop could this message be dropped if the
- * client's queue is getting too large?
- */
-void
-GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *msg,
- int can_drop)
-{
- struct GSC_Client *c;
-
- c = find_client (client);
- if (NULL == c)
- {
- GNUNET_break (0);
- return;
- }
- send_to_client (c, msg, can_drop);
-}
-
-
-/**
- * Test if the client is interested in messages of the given type.
- *
- * @param type message type
- * @param c client to test
- * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
- */
-static int
-type_match (uint16_t type, struct GSC_Client *c)
-{
- unsigned int i;
-
- if (c->tcnt == 0 && c->options != 0)
- return GNUNET_YES; /* peer without handlers and inbound/outbond
- callbacks matches ALL */
- for (i = 0; i < c->tcnt; i++)
- if (type == c->types[i])
- return GNUNET_YES;
- return GNUNET_NO;
-}
-
-
-/**
- * Send a message to all of our current clients that have the right
- * options set.
- *
- * @param partner origin (or destination) of the message (used to check that this peer is
- * known to be connected to the respective client)
- * @param msg message to multicast
- * @param can_drop can this message be discarded if the queue is too long
- * @param options mask to use
- * @param type type of the embedded message, 0 for none
- */
-static void
-send_to_all_clients (const struct GNUNET_PeerIdentity *partner,
- const struct GNUNET_MessageHeader *msg,
- int can_drop,
- uint32_t options,
- uint16_t type)
-{
- struct GSC_Client *c;
- int tm;
-
- for (c = client_head; NULL != c; c = c->next)
- {
- tm = type_match (type, c);
- if (! ( (0 != (c->options & options)) ||
- ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
- (GNUNET_YES == tm) ) ) )
- continue; /* neither options nor type match permit the message */
- if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
- ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
- (GNUNET_YES == tm) ) )
- continue;
- if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
- (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) )
- continue;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending %u message with %u bytes to client interested in messages of type %u.\n",
- options,
- ntohs (msg->size),
- (unsigned int) type);
- GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
- (GNUNET_YES != tm) ||
- (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
- partner)) );
- send_to_client (c, msg, can_drop);
- }
-}
-
-
-/**
- * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
- *
- * @param cls unused
- * @param client new client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
- * @param message the `struct InitMessage` (presumably)
- */
-static void
-handle_client_init (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct InitMessage *im;
- struct InitReplyMessage irm;
- struct GSC_Client *c;
- uint16_t msize;
- const uint16_t *types;
- uint16_t *wtypes;
- unsigned int i;
-
- /* check that we don't have an entry already */
- c = find_client (client);
- if (NULL != c)
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- msize = ntohs (message->size);
- if (msize < sizeof (struct InitMessage))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- GNUNET_SERVER_notification_context_add (notifier, client);
- im = (const struct InitMessage *) message;
- types = (const uint16_t *) &im[1];
- msize -= sizeof (struct InitMessage);
- c = GNUNET_malloc (sizeof (struct GSC_Client) + msize);
- c->client_handle = client;
- c->tcnt = msize / sizeof (uint16_t);
- c->options = ntohl (im->options);
- all_client_options |= c->options;
- c->types = (const uint16_t *) &c[1];
- c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_put (c->connectmap,
- &GSC_my_identity,
- NULL,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- wtypes = (uint16_t *) & c[1];
- for (i = 0; i < c->tcnt; i++)
- wtypes[i] = ntohs (types[i]);
- GSC_TYPEMAP_add (wtypes, c->tcnt);
- GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client connecting to core service is interested in %u message types\n",
- (unsigned int) c->tcnt);
- /* send init reply message */
- irm.header.size = htons (sizeof (struct InitReplyMessage));
- irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
- irm.reserved = htonl (0);
- irm.my_identity = GSC_my_identity;
- send_to_client (c, &irm.header, GNUNET_NO);
- GSC_SESSIONS_notify_client_about_sessions (c);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
- *
- * @param cls unused
- * @param client new client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
- * @param message the `struct SendMessageRequest` (presumably)
- */
-static void
-handle_client_send_request (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct SendMessageRequest *req;
- struct GSC_Client *c;
- struct GSC_ClientActiveRequest *car;
- int is_loopback;
-
- req = (const struct SendMessageRequest *) message;
- c = find_client (client);
- if (NULL == c)
- {
- /* client did not send INIT first! */
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client,
- GNUNET_SYSERR);
- return;
- }
- if (NULL == c->requests)
- c->requests = GNUNET_CONTAINER_multipeermap_create (16,
- GNUNET_NO);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client asked for transmission to `%s'\n",
- GNUNET_i2s (&req->peer));
- is_loopback =
- (0 ==
- memcmp (&req->peer,
- &GSC_my_identity,
- sizeof (struct GNUNET_PeerIdentity)));
- if ((! is_loopback) &&
- (GNUNET_YES !=
- GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
- &req->peer)))
- {
- /* neighbour must have disconnected since request was issued,
- * ignore (client will realize it once it processes the
- * disconnect notification) */
- GNUNET_STATISTICS_update (GSC_stats,
- gettext_noop
- ("# send requests dropped (disconnected)"), 1,
- GNUNET_NO);
- GNUNET_SERVER_receive_done (client,
- GNUNET_OK);
- return;
- }
-
- car = GNUNET_CONTAINER_multipeermap_get (c->requests,
- &req->peer);
- if (NULL == car)
- {
- /* create new entry */
- car = GNUNET_new (struct GSC_ClientActiveRequest);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (c->requests,
- &req->peer,
- car,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
- car->client_handle = c;
- }
- else
- {
- /* dequeue and recycle memory from pending request, there can only
- be at most one per client and peer */
- GNUNET_STATISTICS_update (GSC_stats,
- gettext_noop ("# dequeuing CAR (duplicate request)"),
- 1,
- GNUNET_NO);
- GSC_SESSIONS_dequeue_request (car);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transmission request to `%s' was a duplicate!\n",
- GNUNET_i2s (&req->peer));
- }
- car->target = req->peer;
- car->received_time = GNUNET_TIME_absolute_get ();
- car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
- car->priority = (enum GNUNET_CORE_Priority) ntohl (req->priority);
- car->msize = ntohs (req->size);
- car->smr_id = req->smr_id;
- car->was_solicited = GNUNET_NO;
- if (is_loopback)
- {
- /* loopback, satisfy immediately */
- GSC_CLIENTS_solicit_request (car);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- GSC_SESSIONS_queue_request (car);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Closure for the #client_tokenizer_callback().
- */
-struct TokenizerContext
-{
-
- /**
- * Active request handle for the message.
- */
- struct GSC_ClientActiveRequest *car;
-
- /**
- * How important is this message.
- */
- enum GNUNET_CORE_Priority priority;
-
- /**
- * Is corking allowed (set only once we have the real message).
- */
- int cork;
-
-};
-
-
-/**
- * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
- *
- * @param cls unused
- * @param client the client issuing the request
- * @param message the `struct SendMessage`
- */
-static void
-handle_client_send (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct SendMessage *sm;
- struct GSC_Client *c;
- struct TokenizerContext tc;
- uint16_t msize;
- struct GNUNET_TIME_Relative delay;
-
- msize = ntohs (message->size);
- if (msize < sizeof (struct SendMessage))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client,
- GNUNET_SYSERR);
- return;
- }
- sm = (const struct SendMessage *) message;
- msize -= sizeof (struct SendMessage);
- GNUNET_break (0 == ntohl (sm->reserved));
- c = find_client (client);
- if (NULL == c)
- {
- /* client did not send INIT first! */
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client,
- GNUNET_SYSERR);
- return;
- }
- tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests,
- &sm->peer);
- if (NULL == tc.car)
- {
- /* Must have been that we first approved the request, then got disconnected
- * (which triggered removal of the 'car') and now the client gives us a message
- * just *before* the client learns about the disconnect. Theoretically, we
- * might also now be *again* connected. So this can happen (but should be
- * rare). If it does happen, the message is discarded. */
- GNUNET_STATISTICS_update (GSC_stats,
- gettext_noop ("# messages discarded (session disconnected)"),
- 1,
- GNUNET_NO);
- GNUNET_SERVER_receive_done (client,
- GNUNET_OK);
- return;
- }
- delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
- tc.cork = ntohl (sm->cork);
- tc.priority = (enum GNUNET_CORE_Priority) ntohl (sm->priority);
- if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Client waited %s for transmission of %u bytes to `%s'%s\n",
- GNUNET_STRINGS_relative_time_to_string (delay,
- GNUNET_YES),
- msize,
- GNUNET_i2s (&sm->peer),
- tc.cork ? " (cork)" : " (uncorked)");
- else
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client waited %s for transmission of %u bytes to `%s'%s\n",
- GNUNET_STRINGS_relative_time_to_string (delay,
- GNUNET_YES),
- msize,
- GNUNET_i2s (&sm->peer),
- tc.cork ? " (cork)" : " (uncorked)");
-
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (c->requests,
- &sm->peer,
- tc.car));
- GNUNET_SERVER_mst_receive (client_mst, &tc,
- (const char *) &sm[1],
- msize,
- GNUNET_YES,
- GNUNET_NO);
- GSC_SESSIONS_dequeue_request (tc.car);
- GNUNET_free (tc.car);
- GNUNET_SERVER_receive_done (client,
- GNUNET_OK);
-}
-
-
-/**
- * Functions with this signature are called whenever a complete
- * message is received by the tokenizer. Used by the 'client_mst' for
- * dispatching messages from clients to either the SESSION subsystem
- * or other CLIENT (for loopback).
- *
- * @param cls closure
- * @param client reservation request (`struct GSC_ClientActiveRequest`)
- * @param message the actual message
- */
-static int
-client_tokenizer_callback (void *cls,
- void *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct TokenizerContext *tc = client;
- struct GSC_ClientActiveRequest *car = tc->car;
- char buf[92];
-
- GNUNET_snprintf (buf, sizeof (buf),
- gettext_noop ("# bytes of messages of type %u received"),
- (unsigned int) ntohs (message->type));
- GNUNET_STATISTICS_update (GSC_stats,
- buf,
- ntohs (message->size),
- GNUNET_NO);
- if (0 ==
- memcmp (&car->target,
- &GSC_my_identity,
- sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Delivering message of type %u to myself\n",
- ntohs (message->type));
- GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
- ntohs (message->size),
- GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
- GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
- GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
- ntohs (message->size),
- GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
- GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Delivering message of type %u and size %u to %s\n",
- ntohs (message->type), ntohs (message->size),
- GNUNET_i2s (&car->target));
- GSC_CLIENTS_deliver_message (&car->target, message,
- ntohs (message->size),
- GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
- GSC_CLIENTS_deliver_message (&car->target, message,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
- GSC_SESSIONS_transmit (car,
- message,
- tc->cork,
- tc->priority);
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Free client request records.
- *
- * @param cls NULL
- * @param key identity of peer for which this is an active request
- * @param value the `struct GSC_ClientActiveRequest` to free
- * @return #GNUNET_YES (continue iteration)
- */
-static int
-destroy_active_client_request (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
-{
- struct GSC_ClientActiveRequest *car = value;
-
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (car->
- client_handle->requests,
- &car->target,
- car));
- GSC_SESSIONS_dequeue_request (car);
- GNUNET_free (car);
- return GNUNET_YES;
-}
-
-
-/**
- * A client disconnected, clean up.
- *
- * @param cls closure
- * @param client identification of the client
- */
-static void
-handle_client_disconnect (void *cls,
- struct GNUNET_SERVER_Client *client)
-{
- struct GSC_Client *c;
-
- if (NULL == client)
- return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client %p has disconnected from core service.\n",
- client);
- c = find_client (client);
- if (c == NULL)
- return; /* client never sent INIT */
- GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
- if (c->requests != NULL)
- {
- GNUNET_CONTAINER_multipeermap_iterate (c->requests,
- &destroy_active_client_request,
- NULL);
- GNUNET_CONTAINER_multipeermap_destroy (c->requests);
- }
- GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
- c->connectmap = NULL;
- GSC_TYPEMAP_remove (c->types, c->tcnt);
- GNUNET_free (c);
-
- /* recalculate 'all_client_options' */
- all_client_options = 0;
- for (c = client_head; NULL != c ; c = c->next)
- all_client_options |= c->options;
-}
-
-
-/**
- * Tell a client that we are ready to receive the message.
- *
- * @param car request that is now ready; the responsibility
- * for the handle remains shared between CLIENTS
- * and SESSIONS after this call.
- */
-void
-GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
-{
- struct GSC_Client *c;
- struct SendMessageReady smr;
- struct GNUNET_TIME_Relative delay;
- struct GNUNET_TIME_Relative left;
-
- c = car->client_handle;
- if (GNUNET_YES !=
- GNUNET_CONTAINER_multipeermap_contains (c->connectmap,
- &car->target))
- {
- /* connection has gone down since, drop request */
- GNUNET_assert (0 !=
- memcmp (&car->target,
- &GSC_my_identity,
- sizeof (struct GNUNET_PeerIdentity)));
- GSC_SESSIONS_dequeue_request (car);
- GSC_CLIENTS_reject_request (car,
- GNUNET_NO);
- return;
- }
- delay = GNUNET_TIME_absolute_get_duration (car->received_time);
- left = GNUNET_TIME_absolute_get_duration (car->deadline);
- if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
- GNUNET_STRINGS_relative_time_to_string (delay,
- GNUNET_YES),
- GNUNET_i2s (&car->target),
- (0 == left.rel_value_us)
- ? " (past deadline)"
- : "",
- car->priority);
- smr.header.size = htons (sizeof (struct SendMessageReady));
- smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
- smr.size = htons (car->msize);
- smr.smr_id = car->smr_id;
- smr.peer = car->target;
- send_to_client (c, &smr.header, GNUNET_NO);
-}
-
-
-/**
- * We will never be ready to transmit the given message in (disconnect
- * or invalid request). Frees resources associated with @a car. We
- * don't explicitly tell the client, he'll learn with the disconnect
- * (or violated the protocol).
- *
- * @param car request that now permanently failed; the
- * responsibility for the handle is now returned
- * to CLIENTS (SESSIONS is done with it).
- * @param drop_client #GNUNET_YES if the client violated the protocol
- * and we should thus drop the connection
- */
-void
-GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
- int drop_client)
-{
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (car->
- client_handle->requests,
- &car->target,
- car));
- if (GNUNET_YES == drop_client)
- GNUNET_SERVER_client_disconnect (car->client_handle->client_handle);
- GNUNET_free (car);
-}
-
-
-/**
- * Notify a particular client about a change to existing connection to
- * one of our neighbours (check if the client is interested). Called
- * from 'GSC_SESSIONS_notify_client_about_sessions'.
- *
- * @param client client to notify
- * @param neighbour identity of the neighbour that changed status
- * @param tmap_old previous type map for the neighbour, NULL for connect
- * @param tmap_new updated type map for the neighbour, NULL for disconnect
- */
-void
-GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
- const struct GNUNET_PeerIdentity *neighbour,
- const struct GSC_TypeMap *tmap_old,
- const struct GSC_TypeMap *tmap_new)
-{
- struct ConnectNotifyMessage *cnm;
- size_t size;
- char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
- struct DisconnectNotifyMessage dcm;
- int old_match;
- int new_match;
-
- old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
- new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
- if (old_match == new_match)
- {
- GNUNET_assert (old_match ==
- GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
- neighbour));
- return; /* no change */
- }
- if (old_match == GNUNET_NO)
- {
- /* send connect */
- GNUNET_assert (GNUNET_NO ==
- GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
- neighbour));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_put (client->connectmap,
- neighbour,
- NULL,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- size = sizeof (struct ConnectNotifyMessage);
- cnm = (struct ConnectNotifyMessage *) buf;
- cnm->header.size = htons (size);
- cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
- cnm->reserved = htonl (0);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending `%s' message to client.\n",
- "NOTIFY_CONNECT");
- cnm->peer = *neighbour;
- send_to_client (client, &cnm->header, GNUNET_NO);
- }
- else
- {
- /* send disconnect */
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
- neighbour));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
- neighbour,
- NULL));
- dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage));
- dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
- dcm.reserved = htonl (0);
- dcm.peer = *neighbour;
- send_to_client (client, &dcm.header, GNUNET_NO);
- }
-}
-
-
-/**
- * Notify all clients about a change to existing session.
- * Called from SESSIONS whenever there is a change in sessions
- * or types processed by the respective peer.
- *
- * @param neighbour identity of the neighbour that changed status
- * @param tmap_old previous type map for the neighbour, NULL for connect
- * @param tmap_new updated type map for the neighbour, NULL for disconnect
- */
-void
-GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
- const struct GSC_TypeMap *tmap_old,
- const struct GSC_TypeMap *tmap_new)
-{
- struct GSC_Client *c;
-
- for (c = client_head; NULL != c; c = c->next)
- GSC_CLIENTS_notify_client_about_neighbour (c, neighbour,
- tmap_old, tmap_new);
-}
-
-
-/**
- * Deliver P2P message to interested clients. Caller must have checked
- * that the sending peer actually lists the given message type as one
- * of its types.
- *
- * @param sender peer who sent us the message
- * @param msg the message
- * @param msize number of bytes to transmit
- * @param options options for checking which clients should
- * receive the message
- */
-void
-GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
- const struct GNUNET_MessageHeader *msg,
- uint16_t msize,
- uint32_t options)
-{
- size_t size = msize + sizeof (struct NotifyTrafficMessage);
- char buf[size] GNUNET_ALIGN;
- struct NotifyTrafficMessage *ntm;
-
- if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
- {
- GNUNET_break (0);
- /* recovery strategy: throw performance data away... */
- size = msize + sizeof (struct NotifyTrafficMessage);
- }
- if (! ( (0 != (all_client_options & options)) ||
- (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ))
- return; /* no client cares about this message notification */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core service passes message from `%s' of type %u to client.\n",
- GNUNET_i2s (sender),
- (unsigned int) ntohs (msg->type));
- GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
- ntm = (struct NotifyTrafficMessage *) buf;
- ntm->header.size = htons (size);
- if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
- ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
- else
- ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
- ntm->peer = *sender;
- GNUNET_memcpy (&ntm[1],
- msg,
- msize);
- send_to_all_clients (sender,
- &ntm->header,
- GNUNET_YES,
- options,
- ntohs (msg->type));
-}
-
-
-/**
- * Initialize clients subsystem.
- *
- * @param server handle to server clients connect to
- */
-void
-GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
-{
- static const struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&handle_client_init, NULL,
- GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
- {&GSC_KX_handle_client_monitor_peers, NULL,
- GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
- sizeof (struct GNUNET_MessageHeader)},
- {&handle_client_send_request, NULL,
- GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
- sizeof (struct SendMessageRequest)},
- {&handle_client_send, NULL,
- GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
- {NULL, NULL, 0, 0}
- };
-
- /* setup notification */
- client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL);
- notifier =
- GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
- GNUNET_SERVER_disconnect_notify (server,
- &handle_client_disconnect, NULL);
- GNUNET_SERVER_add_handlers (server, handlers);
-}
-
-
-/**
- * Shutdown clients subsystem.
- */
-void
-GSC_CLIENTS_done ()
-{
- struct GSC_Client *c;
-
- while (NULL != (c = client_head))
- handle_client_disconnect (NULL, c->client_handle);
- if (NULL != notifier)
- {
- GNUNET_SERVER_notification_context_destroy (notifier);
- notifier = NULL;
- }
- if (NULL != client_mst)
- {
- GNUNET_SERVER_mst_destroy (client_mst);
- client_mst = NULL;
- }
-}
-
-/* end of gnunet-service-core_clients.c */
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2009, 2010, 2011 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, 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file core/gnunet-service-core_clients.h
- * @brief code for managing interactions with clients of core service
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CORE_CLIENTS_H
-#define GNUNET_SERVICE_CORE_CLIENTS_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet-service-core.h"
-#include "gnunet-service-core_typemap.h"
-
-
-/**
- * Send a message to one of our clients.
- *
- * @param client target for the message
- * @param msg message to transmit
- * @param can_drop could this message be dropped if the
- * client's queue is getting too large?
- */
-void
-GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *msg,
- int can_drop);
-
-
-/**
- * Notify a particular client about a change to existing connection to
- * one of our neighbours (check if the client is interested). Called
- * from 'GSC_SESSIONS_notify_client_about_sessions'.
- *
- * @param client client to notify
- * @param neighbour identity of the neighbour that changed status
- * @param tmap_old previous type map for the neighbour, NULL for disconnect
- * @param tmap_new updated type map for the neighbour, NULL for disconnect
- */
-void
-GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
- const struct GNUNET_PeerIdentity *neighbour,
- const struct GSC_TypeMap *tmap_old,
- const struct GSC_TypeMap *tmap_new);
-
-
-/**
- * Notify all clients about a change to existing session.
- * Called from SESSIONS whenever there is a change in sessions
- * or types processed by the respective peer.
- *
- * @param neighbour identity of the neighbour that changed status
- * @param tmap_old previous type map for the neighbour, NULL for disconnect
- * @param tmap_new updated type map for the neighbour, NULL for disconnect
- */
-void
-GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
- const struct GSC_TypeMap *tmap_old,
- const struct GSC_TypeMap *tmap_new);
-
-
-/**
- * Deliver P2P message to interested clients. Caller must have checked
- * that the sending peer actually lists the given message type as one
- * of its types.
- *
- * @param sender peer who sent us the message
- * @param msg the message
- * @param msize number of bytes to transmit
- * @param options options for checking which clients should
- * receive the message
- */
-void
-GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
- const struct GNUNET_MessageHeader *msg,
- uint16_t msize,
- uint32_t options);
-
-
-/**
- * Tell a client that we are ready to receive the message.
- *
- * @param car request that is now ready; the responsibility
- * for the handle remains shared between CLIENTS
- * and SESSIONS after this call.
- */
-void
-GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car);
-
-
-/**
- * We will never be ready to transmit the given message in (disconnect
- * or invalid request). Frees resources associated with @a car. We
- * don't explicitly tell the client, he'll learn with the disconnect
- * (or violated the protocol).
- *
- * @param car request that now permanently failed; the
- * responsibility for the handle is now returned
- * to CLIENTS (SESSIONS is done with it).
- * @param drop_client #GNUNET_YES if the client violated the protocol
- * and we should thus drop the connection
- */
-void
-GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
- int drop_client);
-
-
-/**
- * Initialize clients subsystem.
- *
- * @param server handle to server clients connect to
- */
-void
-GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Shutdown clients subsystem.
- */
-void
-GSC_CLIENTS_done (void);
-
-#endif
-/* end of gnunet-service-core_clients.h */
#include "platform.h"
#include "gnunet-service-core_kx.h"
#include "gnunet-service-core.h"
-#include "gnunet-service-core_clients.h"
#include "gnunet-service-core_sessions.h"
#include "gnunet_statistics_service.h"
#include "gnunet_transport_core_service.h"
static struct GNUNET_SCHEDULER_Task *rekey_task;
/**
- * Notification context for all monitors.
+ * Notification context for broadcasting to monitors.
*/
-static struct GNUNET_SERVER_NotificationContext *nc;
-
-
-/**
- * Inform the given monitor about the KX state of
- * the given peer.
- *
- * @param client client to inform
- * @param kx key exchange state to inform about
- */
-static void
-monitor_notify (struct GNUNET_SERVER_Client *client,
- struct GSC_KeyExchangeInfo *kx)
-{
- struct MonitorNotifyMessage msg;
-
- msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
- msg.header.size = htons (sizeof (msg));
- msg.state = htonl ((uint32_t) kx->status);
- msg.peer = *kx->peer;
- msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
- GNUNET_SERVER_notification_context_unicast (nc,
- client,
- &msg.header,
- GNUNET_NO);
-}
+static struct GNUNET_NotificationContext *nc;
/**
msg.state = htonl ((uint32_t) kx->status);
msg.peer = *kx->peer;
msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
- GNUNET_SERVER_notification_context_broadcast (nc,
- &msg.header,
- GNUNET_NO);
+ GNUNET_notification_context_broadcast (nc,
+ &msg.header,
+ GNUNET_NO);
kx->last_notify_timeout = kx->timeout;
}
* Initialize KX subsystem.
*
* @param pk private key to use for the peer
- * @param server the server of the CORE service
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
int
-GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk,
- struct GNUNET_SERVER_Handle *server)
+GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
{
struct GNUNET_MQ_MessageHandler handlers[] = {
GNUNET_MQ_hd_fixed_size (ephemeral_key,
GNUNET_MQ_handler_end()
};
- nc = GNUNET_SERVER_notification_context_create (server,
- 1);
my_private_key = pk;
GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
&GSC_my_identity.public_key);
return GNUNET_SYSERR;
}
sign_ephemeral_key ();
+ nc = GNUNET_notification_context_create (1);
rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
&do_rekey,
NULL);
- mst = GNUNET_SERVER_mst_create (&deliver_message, NULL);
+ mst = GNUNET_SERVER_mst_create (&deliver_message,
+ NULL);
transport
= GNUNET_TRANSPORT_core_connect (GSC_cfg,
&GSC_my_identity,
}
if (NULL != nc)
{
- GNUNET_SERVER_notification_context_destroy (nc);
+ GNUNET_notification_context_destroy (nc);
nc = NULL;
}
}
* request. All current peers are returned, regardless of which
* message types they accept.
*
- * @param cls unused
- * @param client client sending the iteration request
- * @param message iteration request message
+ * @param mq message queue to add for monitoring
*/
void
-GSC_KX_handle_client_monitor_peers (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
+GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq)
{
- struct MonitorNotifyMessage done_msg;
+ struct GNUNET_MQ_Envelope *env;
+ struct MonitorNotifyMessage *done_msg;
struct GSC_KeyExchangeInfo *kx;
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- GNUNET_SERVER_notification_context_add (nc,
- client);
+ GNUNET_notification_context_add (nc,
+ mq);
for (kx = kx_head; NULL != kx; kx = kx->next)
- monitor_notify (client, kx);
- done_msg.header.size = htons (sizeof (struct MonitorNotifyMessage));
- done_msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
- done_msg.state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
- memset (&done_msg.peer,
- 0,
- sizeof (struct GNUNET_PeerIdentity));
- done_msg.timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
- GNUNET_SERVER_notification_context_unicast (nc,
- client,
- &done_msg.header,
- GNUNET_NO);
+ {
+ struct GNUNET_MQ_Envelope *env;
+ struct MonitorNotifyMessage *msg;
+
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
+ msg->state = htonl ((uint32_t) kx->status);
+ msg->peer = *kx->peer;
+ msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout);
+ GNUNET_MQ_send (mq,
+ env);
+ }
+ env = GNUNET_MQ_msg (done_msg,
+ GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
+ done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED);
+ done_msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
+ GNUNET_MQ_send (mq,
+ env);
}
* Initialize KX subsystem.
*
* @param pk private key to use for the peer
- * @param server the server of the CORE service
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
int
-GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk,
- struct GNUNET_SERVER_Handle *server);
+GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk);
/**
* request. All current peers are returned, regardless of which
* message types they accept.
*
- * @param cls unused
- * @param client client sending the iteration request
- * @param message iteration request message
+ * @param mq message queue to add for monitoring
*/
void
-GSC_KX_handle_client_monitor_peers (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message);
+GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq);
#endif
#include "gnunet-service-core_kx.h"
#include "gnunet-service-core_typemap.h"
#include "gnunet-service-core_sessions.h"
-#include "gnunet-service-core_clients.h"
#include "gnunet_constants.h"
#include "core.h"