-style fix
[oweals/gnunet.git] / src / core / gnunet-service-core_clients.c
index 0b1616c9795455c62a5affffe5babafa9bc8e47f..5f745e3bc283e7e70bb8b84c09151e872a55b1ec 100644 (file)
@@ -33,6 +33,7 @@
 #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
@@ -72,7 +73,12 @@ struct GSC_Client
    * Map of peer identities to active transmission requests of this
    * client to the peer (of type 'struct GSC_ClientActiveRequest').
    */
-  struct GNUNET_CONTAINER_MultiHashMap *requests;
+  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,
@@ -89,6 +95,11 @@ struct GSC_Client
 };
 
 
+/**
+ * Big "or" of all client options.
+ */
+static uint32_t all_client_options;
+
 /**
  * Head of linked list of our clients.
  */
@@ -137,16 +148,13 @@ find_client (struct GNUNET_SERVER_Client *client)
  *        client's queue is getting too large?
  */
 static void
-send_to_client (struct GSC_Client *client, 
-               const struct GNUNET_MessageHeader *msg,
-                int can_drop)
+send_to_client (struct GSC_Client *client,
+                const struct GNUNET_MessageHeader *msg, int can_drop)
 {
-#if DEBUG_CORE
   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));
-#endif
   GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
                                               msg, can_drop);
 }
@@ -162,8 +170,8 @@ send_to_client (struct GSC_Client *client,
  */
 void
 GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
-                           const struct GNUNET_MessageHeader *msg,
-                           int can_drop)
+                            const struct GNUNET_MessageHeader *msg,
+                            int can_drop)
 {
   struct GSC_Client *c;
 
@@ -185,12 +193,13 @@ GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client,
  * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not.
  */
 static int
-type_match (uint16_t type,
-           struct GSC_Client *c)
+type_match (uint16_t type, struct GSC_Client *c)
 {
   unsigned int i;
 
-  for (i=0;i<c->tcnt;i++)
+  if (c->tcnt == 0)
+    return GNUNET_YES;          /* peer without handlers matches ALL */
+  for (i = 0; i < c->tcnt; i++)
     if (type == c->types[i])
       return GNUNET_YES;
   return GNUNET_NO;
@@ -201,30 +210,45 @@ type_match (uint16_t type,
  * 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_MessageHeader *msg, 
-                    int can_drop,
-                     int options,
-                    uint16_t type)
+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; c != NULL; c = c->next)
   {
-    if (! ( (0 != (c->options & options)) ||
-           ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
-             (GNUNET_YES == type_match (type, c)) ) ) )
-      continue; /* skip */
-#if DEBUG_CORE > 1
+    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 message of type %u to client.\n",
-               (unsigned int) ntohs (msg->type));
-#endif
+                "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);
   }
 }
@@ -272,27 +296,29 @@ handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
   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);
-#if DEBUG_CORE
+  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", 
+              "Client connecting to core service is interested in %u message types\n",
               (unsigned int) c->tcnt);
-#endif
   /* 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);
-  if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
-    GSC_SESSIONS_notify_client_about_sessions (c);
+  GSC_SESSIONS_notify_client_about_sessions (c);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -302,7 +328,7 @@ handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
  *
  * @param cls unused
  * @param client new client that sent CORE_SEND_REQUEST
- * @param message the 'struct InitMessage' (presumably)
+ * @param message the 'struct SendMessageRequest' (presumably)
  */
 static void
 handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
@@ -311,6 +337,7 @@ handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
   const struct SendMessageRequest *req;
   struct GSC_Client *c;
   struct GSC_ClientActiveRequest *car;
+  int is_loopback;
 
   req = (const struct SendMessageRequest *) message;
   c = find_client (client);
@@ -322,30 +349,60 @@ handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
   if (c->requests == NULL)
-    c->requests = GNUNET_CONTAINER_multihashmap_create (16);
-  car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
+    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 (car == NULL)
   {
     /* create new entry */
     car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest));
     GNUNET_assert (GNUNET_OK ==
-                   GNUNET_CONTAINER_multihashmap_put (c->requests,
-                                                      &req->peer.hashPubKey,
+                   GNUNET_CONTAINER_multipeermap_put (c->requests,
+                                                      &req->peer,
                                                       car,
                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
     car->client_handle = c;
   }
+  else
+  {
+    GSC_SESSIONS_dequeue_request (car);
+  }
   car->target = req->peer;
   car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
   car->priority = ntohl (req->priority);
   car->msize = ntohs (req->size);
   car->smr_id = req->smr_id;
   car->was_solicited = GNUNET_NO;
-  if (0 ==
-      memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
+  if (is_loopback)
+  {
+    /* loopback, satisfy immediately */
     GSC_CLIENTS_solicit_request (car);
-  else
-    GSC_SESSIONS_queue_request (car);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  GSC_SESSIONS_queue_request (car);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -358,7 +415,7 @@ struct TokenizerContext
 
   /**
    * Active request handle for the message.
-   */ 
+   */
   struct GSC_ClientActiveRequest *car;
 
   /**
@@ -404,28 +461,37 @@ handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  tc.car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey);
+  tc.car =
+      GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
   if (NULL == tc.car)
   {
-    /* client did not request transmission first! */
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    /* 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;
   }
   GNUNET_assert (GNUNET_YES ==
-                GNUNET_CONTAINER_multihashmap_remove (c->requests, 
-                                                      &sm->peer.hashPubKey,
-                                                      tc.car));
+                 GNUNET_CONTAINER_multipeermap_remove (c->requests,
+                                                       &sm->peer,
+                                                       tc.car));
   tc.cork = ntohl (sm->cork);
-  GNUNET_SERVER_mst_receive (client_mst,
-                            &tc, 
-                            (const char*) &sm[1], msize,
-                            GNUNET_YES,
-                            GNUNET_NO);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Client asked for transmission of %u bytes to `%s' %s\n", msize,
+              GNUNET_i2s (&sm->peer), tc.cork ? "now" : "");
+  GNUNET_SERVER_mst_receive (client_mst, &tc, (const char *) &sm[1], msize,
+                             GNUNET_YES, GNUNET_NO);
   if (0 !=
-      memcmp (&tc.car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))  
+      memcmp (&tc.car->target, &GSC_my_identity,
+              sizeof (struct GNUNET_PeerIdentity)))
     GSC_SESSIONS_dequeue_request (tc.car);
-  GNUNET_free (tc.car);  
+  GNUNET_free (tc.car);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -440,29 +506,52 @@ handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
  * @param client reservation request ('struct GSC_ClientActiveRequest')
  * @param message the actual message
  */
-static void
+static int
 client_tokenizer_callback (void *cls, void *client,
-                          const struct GNUNET_MessageHeader *message)
+                           const struct GNUNET_MessageHeader *message)
 {
-  struct TokenizerContext *tc = cls;
+  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)))  
+      memcmp (&car->target, &GSC_my_identity,
+              sizeof (struct GNUNET_PeerIdentity)))
   {
-    GSC_CLIENTS_deliver_message (&GSC_my_identity, 
-                                NULL, 0,
-                                message,
+    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_INBOUND | GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);  
-    GSC_CLIENTS_deliver_message (&GSC_my_identity, 
-                                NULL, 0,
-                                message,
+                                GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
+    GSC_CLIENTS_deliver_message (&GSC_my_identity, message,
                                 sizeof (struct GNUNET_MessageHeader),
-                                GNUNET_CORE_OPTION_SEND_HDR_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);  
+                                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 to %s\n", ntohs (message->type),
+                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);
+  }
+  return GNUNET_OK;
 }
 
 
@@ -472,18 +561,20 @@ client_tokenizer_callback (void *cls, void *client,
  * @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)
+ * @return #GNUNET_YES (continue iteration)
  */
 static int
-destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
+destroy_active_client_request (void *cls,
+                              const struct GNUNET_PeerIdentity *key,
                                void *value)
 {
   struct GSC_ClientActiveRequest *car = value;
 
   GNUNET_assert (GNUNET_YES ==
-                GNUNET_CONTAINER_multihashmap_remove (car->client_handle->requests,
-                                                      &car->target.hashPubKey,
-                                                      car));
+                 GNUNET_CONTAINER_multipeermap_remove (car->
+                                                       client_handle->requests,
+                                                       &car->target,
+                                                       car));
   GSC_SESSIONS_dequeue_request (car);
   GNUNET_free (car);
   return GNUNET_YES;
@@ -497,32 +588,34 @@ destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
  * @param client identification of the client
  */
 static void
-handle_client_disconnect (void *cls,
-                         struct GNUNET_SERVER_Client *client)
+handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
 {
   struct GSC_Client *c;
 
   if (client == NULL)
     return;
-#if DEBUG_CORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Client %p has disconnected from core service.\n", client);
-#endif
   c = find_client (client);
   if (c == NULL)
-    return; /* client never sent INIT */
-  GNUNET_CONTAINER_DLL_remove (client_head,
-                              client_tail,
-                              c);
+    return;                     /* client never sent INIT */
+  GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
   if (c->requests != NULL)
   {
-    GNUNET_CONTAINER_multihashmap_iterate (c->requests,
+    GNUNET_CONTAINER_multipeermap_iterate (c->requests,
                                            &destroy_active_client_request,
                                            NULL);
-    GNUNET_CONTAINER_multihashmap_destroy (c->requests);
+    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;
 }
 
 
@@ -540,6 +633,18 @@ GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
   struct SendMessageReady smr;
 
   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);
+    return;
+  }
   smr.header.size = htons (sizeof (struct SendMessageReady));
   smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
   smr.size = htons (car->msize);
@@ -561,7 +666,11 @@ void
 GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
 {
   GNUNET_assert (GNUNET_YES ==
-                destroy_active_client_request (NULL, &car->target.hashPubKey, car));  
+                 GNUNET_CONTAINER_multipeermap_remove (car->
+                                                       client_handle->requests,
+                                                       &car->target,
+                                                       car));
+  GNUNET_free (car);
 }
 
 
@@ -572,23 +681,19 @@ GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car)
  *
  * @param client client to notify
  * @param neighbour identity of the neighbour that changed status
- * @param atsi performance information about neighbour
- * @param atsi_count number of entries in 'ats' array
- * @param tmap_old previous type map for the neighbour, NULL for disconnect
+ * @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
-GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
-                                          const struct GNUNET_PeerIdentity *neighbour,
-                                          const struct GNUNET_TRANSPORT_ATS_Information *atsi,
-                                          unsigned int atsi_count,
-                                          const struct GSC_TypeMap *tmap_old,
-                                          const struct GSC_TypeMap *tmap_new)
+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];
-  struct GNUNET_TRANSPORT_ATS_Information *a;
+  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
   struct DisconnectNotifyMessage dcm;
   int old_match;
   int new_match;
@@ -596,40 +701,43 @@ GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
   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)
-    return; /* no change */
+  {
+    GNUNET_assert (old_match ==
+                   GNUNET_CONTAINER_multipeermap_contains (client->connectmap,
+                                                           neighbour));
+    return;                     /* no change */
+  }
   if (old_match == GNUNET_NO)
   {
-    /* send connect */  
-    size =
-      sizeof (struct ConnectNotifyMessage) +
-      (atsi_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
-    if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
-      {
-       GNUNET_break (0);
-       /* recovery strategy: throw away performance data */
-       atsi_count = 0;
-       size = sizeof (struct ConnectNotifyMessage);
-      }
+    /* 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->ats_count = htonl (atsi_count);
-    a = &cnm->ats;
-    memcpy (a, atsi,
-           sizeof (struct GNUNET_TRANSPORT_ATS_Information) * atsi_count);
-    a[atsi_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
-    a[atsi_count].value = htonl (0);
-#if DEBUG_CORE
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-               "Sending `%s' message to client.\n",
+    cnm->reserved = htonl (0);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
                 "NOTIFY_CONNECT");
-#endif
     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);
@@ -645,35 +753,29 @@ GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client,
  * or types processed by the respective peer.
  *
  * @param neighbour identity of the neighbour that changed status
- * @param atsi performance information about neighbour
- * @param atsi_count number of entries in 'ats' array
- * @param tmap_old previous type map for the neighbour, NULL for disconnect
+ * @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
-GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour,
-                                           const struct GNUNET_TRANSPORT_ATS_Information *atsi,
-                                           unsigned int atsi_count,
-                                           const struct GSC_TypeMap *tmap_old,
-                                           const struct GSC_TypeMap *tmap_new)
+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; c != NULL; c = c->next)
-    GDS_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi,
-                                              atsi_count, 
-                                              tmap_old, tmap_new);
+    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 
+ * that the sending peer actually lists the given message type as one
  * of its types.
  *
- * @param sender peer who sent us the message 
- * @param atsi performance information about neighbour
- * @param atsi_count number of entries in 'ats' array
+ * @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
@@ -681,51 +783,37 @@ GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *ne
  */
 void
 GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
-                            const struct GNUNET_TRANSPORT_ATS_Information *atsi,
-                            unsigned int atsi_count,
-                            const struct GNUNET_MessageHeader *msg,
-                            uint16_t msize,
-                            int options)
+                             const struct GNUNET_MessageHeader *msg,
+                             uint16_t msize,
+                             uint32_t options)
 {
-  size_t size = msize + sizeof (struct NotifyTrafficMessage) +
-      atsi_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
-  char buf[size];
+  size_t size = msize + sizeof (struct NotifyTrafficMessage);
+  char buf[size] GNUNET_ALIGN;
   struct NotifyTrafficMessage *ntm;
-  struct GNUNET_TRANSPORT_ATS_Information *a;
 
-  if (0 == options)
-  {
-    GNUNET_snprintf (buf, sizeof (buf),
-                    gettext_noop ("# bytes of messages of type %u received"),
-                    (unsigned int) ntohs (msg->type));
-    GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO);
-  }
   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     /* recovery strategy: throw performance data away... */
-    atsi_count = 0;
     size = msize + sizeof (struct NotifyTrafficMessage);
   }
-#if DEBUG_CORE
+  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 `%4s' of type %u to client.\n",
-              GNUNET_i2s (sender),
-              (unsigned int) ntohs (msg->type));
-#endif
+              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);
-  ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
-  ntm->ats_count = htonl (atsi_count);
+  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;
-  a = &ntm->ats;
-  memcpy (a, atsi,
-          sizeof (struct GNUNET_TRANSPORT_ATS_Information) * atsi_count);
-  a[atsi_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
-  a[atsi_count].value = htonl (0);
-  memcpy (&a[atsi_count + 1], msg, msize);
-  send_to_all_clients (&ntm->header, GNUNET_YES, 
-                      options, ntohs (msg->type));
+  memcpy (&ntm[1], msg, msize);
+  send_to_all_clients (sender, &ntm->header, GNUNET_YES, options,
+                       ntohs (msg->type));
 }
 
 
@@ -743,10 +831,6 @@ GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
     {&GSC_SESSIONS_handle_client_iterate_peers, NULL,
      GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
      sizeof (struct GNUNET_MessageHeader)},
-    {&GSC_SESSIONS_handle_client_have_peer, NULL,
-     GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
-     sizeof (struct GNUNET_MessageHeader) +
-     sizeof (struct GNUNET_PeerIdentity)},
     {&handle_client_send_request, NULL,
      GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
      sizeof (struct SendMessageRequest)},
@@ -772,12 +856,18 @@ GSC_CLIENTS_done ()
 {
   struct GSC_Client *c;
 
-  while (NULL != (c = client_head))  
+  while (NULL != (c = client_head))
     handle_client_disconnect (NULL, c->client_handle);
-  GNUNET_SERVER_notification_context_destroy (notifier);
-  notifier = NULL;
-  GNUNET_SERVER_mst_destroy (client_mst);
-  client_mst = NULL;
+  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 */