converting core service to new service API
authorChristian Grothoff <christian@grothoff.org>
Tue, 20 Sep 2016 15:14:05 +0000 (15:14 +0000)
committerChristian Grothoff <christian@grothoff.org>
Tue, 20 Sep 2016 15:14:05 +0000 (15:14 +0000)
src/core/Makefile.am
src/core/core_api.c
src/core/gnunet-service-core.c
src/core/gnunet-service-core.h
src/core/gnunet-service-core_clients.c [deleted file]
src/core/gnunet-service-core_clients.h [deleted file]
src/core/gnunet-service-core_kx.c
src/core/gnunet-service-core_kx.h
src/core/gnunet-service-core_sessions.c

index a99f74af60f5257d55bc9b3e8caad174032efce7..aea64fa34cbbd55902152e75205d115d22941d7e 100644 (file)
@@ -41,7 +41,6 @@ bin_PROGRAMS = \
 
 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
index 6055b99c1acad9060eaf4d84c60ca73f6efce6a7..67f17352ddfd9170f8117b04332fabd6b0d4c28a 100644 (file)
@@ -541,11 +541,12 @@ handle_notify_inbound (void *cls,
   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;
index f9391e61690ada9c40754ae921948b2934f9d454..acaa100929433d7581b64a275c6f26ff33e1fdb4 100644 (file)
@@ -1,6 +1,6 @@
 /*
      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.
@@ -49,9 +113,739 @@ const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
 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);
+  }  
+}
 
 
 /**
@@ -63,9 +857,12 @@ static struct GNUNET_SERVER_Handle *GSC_server;
 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 ();
@@ -79,23 +876,42 @@ shutdown_task (void *cls)
 }
 
 
+/**
+ * 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",
@@ -111,20 +927,18 @@ run (void *cls,
                                        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));
@@ -132,19 +946,32 @@ run (void *cls,
 
 
 /**
- * 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 */
index 068a2f84f554c97e808976add7c20469df19a3ee..86ac333b5405655235c73cca6dd0b617bc4e172b 100644 (file)
@@ -29,6 +29,8 @@
 #include "gnunet_statistics_service.h"
 #include "gnunet_core_service.h"
 #include "core.h"
+#include "gnunet-service-core_typemap.h"
+
 
 /**
  * Opaque handle to a client.
@@ -99,6 +101,84 @@ struct GSC_ClientActiveRequest
 };
 
 
+/**
+ * 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.
  */
diff --git a/src/core/gnunet-service-core_clients.c b/src/core/gnunet-service-core_clients.c
deleted file mode 100644 (file)
index 5db33f0..0000000
+++ /dev/null
@@ -1,960 +0,0 @@
-/*
-     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 */
diff --git a/src/core/gnunet-service-core_clients.h b/src/core/gnunet-service-core_clients.h
deleted file mode 100644 (file)
index 4947f33..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-     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 */
index 6f6786d891b6090ff41ae565d58f46728544f781..6743ce21537eb063bfe058f36f8009738be35bed 100644 (file)
@@ -26,7 +26,6 @@
 #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"
@@ -392,34 +391,9 @@ static struct GSC_KeyExchangeInfo *kx_tail;
 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;
 
 
 /**
@@ -453,9 +427,9 @@ monitor_notify_all (struct GSC_KeyExchangeInfo *kx)
   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;
 }
 
@@ -1807,12 +1781,10 @@ do_rekey (void *cls)
  * 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,
@@ -1834,8 +1806,6 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk,
     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);
@@ -1848,10 +1818,12 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk,
     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,
@@ -1902,7 +1874,7 @@ GSC_KX_done ()
   }
   if (NULL != nc)
   {
-    GNUNET_SERVER_notification_context_destroy (nc);
+    GNUNET_notification_context_destroy (nc);
     nc = NULL;
   }
 }
@@ -1940,34 +1912,36 @@ GSC_NEIGHBOURS_check_excess_bandwidth (const struct GSC_KeyExchangeInfo *kxinfo)
  * 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);
 }
 
 
index 8614f090fec6b2292dd0acb1486d63b164e1c5d5..28293e6072143de5e920c797e7f2c72ca2a95a1e 100644 (file)
@@ -53,12 +53,10 @@ GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
  * 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);
 
 
 /**
@@ -94,14 +92,10 @@ GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *target);
  * 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
index ef5285b45761321c6b09d1ddfa7407774abd140c..036fd1425ff0c2bfd6b5fdc78117cb8c87cf9aa1 100644 (file)
@@ -28,7 +28,6 @@
 #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"