Check that you are not present in trail twice
[oweals/gnunet.git] / src / transport / gnunet-service-transport_clients.c
index c3ef42652f082f84ba61eaecd807502d99991c4b..af15023df15b240a9358598c3b988babbb6889dc 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2010,2011 Christian Grothoff (and other contributing authors)
+     (C) 2010-2014 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -190,19 +190,34 @@ struct AddressToStringContext *a2s_tail;
 /**
  * Head of linked list of monitoring clients.
  */
-static struct MonitoringClient *monitoring_clients_head;
+static struct MonitoringClient *peer_monitoring_clients_head;
 
 /**
  * Tail of linked list of monitoring clients.
  */
-static struct MonitoringClient *monitoring_clients_tail;
+static struct MonitoringClient *peer_monitoring_clients_tail;
+
+/**
+ * Head of linked list of validation monitoring clients.
+ */
+static struct MonitoringClient *val_monitoring_clients_head;
+
+/**
+ * Tail of linked list of validation monitoring clients.
+ */
+static struct MonitoringClient *val_monitoring_clients_tail;
 
 /**
  * Notification context, to send updates on changes to active addresses
  * of our neighbours.
  */
-static struct GNUNET_SERVER_NotificationContext *nc;
+static struct GNUNET_SERVER_NotificationContext *peer_nc;
 
+/**
+ * Notification context, to send updates on changes to active addresses
+ * of our neighbours.
+ */
+static struct GNUNET_SERVER_NotificationContext *val_nc;
 
 /**
  * Find the internal handle associated with the given client handle
@@ -247,15 +262,17 @@ setup_client (struct GNUNET_SERVER_Client *client)
  * Find the handle to the monitoring client associated with the given
  * client handle
  *
+ * @param head the head of the client queue to look in
  * @param client server's client handle to look up
  * @return handle to the monitoring client
  */
 static struct MonitoringClient *
-lookup_monitoring_client (struct GNUNET_SERVER_Client *client)
+lookup_monitoring_client (struct MonitoringClient *head,
+                          struct GNUNET_SERVER_Client *client)
 {
   struct MonitoringClient *mc;
 
-  for (mc = monitoring_clients_head; NULL != mc; mc = mc->next)
+  for (mc = head; NULL != mc; mc = mc->next)
     if (mc->client == client)
       return mc;
   return NULL;
@@ -272,27 +289,59 @@ lookup_monitoring_client (struct GNUNET_SERVER_Client *client)
  * @return handle to the new monitoring client
  */
 static struct MonitoringClient *
-setup_monitoring_client (struct GNUNET_SERVER_Client *client,
-                         struct GNUNET_PeerIdentity *peer)
+setup_peer_monitoring_client (struct GNUNET_SERVER_Client *client,
+                              struct GNUNET_PeerIdentity *peer)
 {
   struct MonitoringClient *mc;
   static struct GNUNET_PeerIdentity all_zeros;
 
-  GNUNET_assert (lookup_monitoring_client (client) == NULL);
+  GNUNET_assert (lookup_monitoring_client (peer_monitoring_clients_head, client) == NULL);
   mc = GNUNET_new (struct MonitoringClient);
   mc->client = client;
   mc->peer = *peer;
-  GNUNET_CONTAINER_DLL_insert (monitoring_clients_head,
-                               monitoring_clients_tail,
-                               mc);
-  GNUNET_SERVER_notification_context_add (nc, client);
+  GNUNET_CONTAINER_DLL_insert (peer_monitoring_clients_head, peer_monitoring_clients_tail, mc);
+  GNUNET_SERVER_notification_context_add (peer_nc, client);
 
   if (0 != memcmp (peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity)))
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Client %p started monitoring of the peer `%s'\n",
                 mc, GNUNET_i2s (peer));
   else
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Client %p started monitoring all peers\n", mc);
+  return mc;
+}
+
+
+/**
+ * Setup a new monitoring client using the given server client handle and
+ * the peer identity.
+ *
+ * @param client server's client handle to create our internal handle for
+ * @param peer identity of the peer to monitor the addresses of,
+ *             zero to monitor all neighrours.
+ * @return handle to the new monitoring client
+ */
+static struct MonitoringClient *
+setup_val_monitoring_client (struct GNUNET_SERVER_Client *client,
+                             struct GNUNET_PeerIdentity *peer)
+{
+  struct MonitoringClient *mc;
+  static struct GNUNET_PeerIdentity all_zeros;
+
+  GNUNET_assert (lookup_monitoring_client (val_monitoring_clients_head, client) == NULL);
+  mc = GNUNET_new (struct MonitoringClient);
+  mc->client = client;
+  mc->peer = *peer;
+  GNUNET_CONTAINER_DLL_insert (val_monitoring_clients_head, val_monitoring_clients_tail, mc);
+  GNUNET_SERVER_notification_context_add (val_nc, client);
+
+  if (0 != memcmp (peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity)))
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Client %p started monitoring of the peer `%s'\n",
+                mc, GNUNET_i2s (peer));
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Client %p started monitoring all peers\n", mc);
   return mc;
 }
@@ -309,7 +358,9 @@ setup_monitoring_client (struct GNUNET_SERVER_Client *client,
  * @return number of bytes written to @a buf
  */
 static size_t
-transmit_to_client_callback (void *cls, size_t size, void *buf)
+transmit_to_client_callback (void *cls,
+                             size_t size,
+                             void *buf)
 {
   struct TransportClient *tc = cls;
   struct ClientMessageQueueEntry *q;
@@ -381,9 +432,10 @@ unicast (struct TransportClient *tc,
   if ((tc->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                _
-                ("Dropping message of type %u and size %u, have %u/%u messages pending\n"),
-                ntohs (msg->type), ntohs (msg->size), tc->message_count,
+                _("Dropping message of type %u and size %u, have %u/%u messages pending\n"),
+                ntohs (msg->type),
+                ntohs (msg->size),
+                tc->message_count,
                 MAX_PENDING);
     GNUNET_STATISTICS_update (GST_stats,
                               gettext_noop
@@ -416,7 +468,8 @@ unicast (struct TransportClient *tc,
  * @param client identification of the client
  */
 static void
-client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
+client_disconnect_notification (void *cls,
+                                struct GNUNET_SERVER_Client *client)
 {
   struct TransportClient *tc;
   struct MonitoringClient *mc;
@@ -424,11 +477,19 @@ client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
 
   if (client == NULL)
     return;
-  mc = lookup_monitoring_client (client);
+  mc = lookup_monitoring_client (peer_monitoring_clients_head, client);
+  if (mc != NULL)
+  {
+    GNUNET_CONTAINER_DLL_remove (peer_monitoring_clients_head,
+                                 peer_monitoring_clients_tail,
+                                 mc);
+    GNUNET_free (mc);
+  }
+  mc = lookup_monitoring_client (val_monitoring_clients_head, client);
   if (mc != NULL)
   {
-    GNUNET_CONTAINER_DLL_remove (monitoring_clients_head,
-                                 monitoring_clients_tail,
+    GNUNET_CONTAINER_DLL_remove (val_monitoring_clients_head,
+                                 val_monitoring_clients_tail,
                                  mc);
     GNUNET_free (mc);
   }
@@ -459,9 +520,11 @@ client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
  * Function called for each of our connected neighbours.  Notify the
  * client about the existing neighbour.
  *
- * @param cls the 'struct TransportClient' to notify
+ * @param cls the `struct TransportClient *` to notify
  * @param peer identity of the neighbour
  * @param address the address
+ * @param state the current state of the peer
+ * @param state_timeout the time out for the state
  * @param bandwidth_in inbound bandwidth in NBO
  * @param bandwidth_out outbound bandwidth in NBO
  */
@@ -469,6 +532,8 @@ static void
 notify_client_about_neighbour (void *cls,
                                const struct GNUNET_PeerIdentity *peer,
                                const struct GNUNET_HELLO_Address *address,
+                               enum GNUNET_TRANSPORT_PeerState state,
+                               struct GNUNET_TIME_Absolute state_timeout,
                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
 {
@@ -477,6 +542,9 @@ notify_client_about_neighbour (void *cls,
   size_t size = sizeof (struct ConnectInfoMessage);
   char buf[size] GNUNET_ALIGN;
 
+  if (GNUNET_NO == GST_neighbours_test_connected (peer))
+    return;
+
   GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
   cim = (struct ConnectInfoMessage *) buf;
   cim->header.size = htons (size);
@@ -498,7 +566,8 @@ notify_client_about_neighbour (void *cls,
  * @param message the start message that was sent
  */
 static void
-clients_handle_start (void *cls, struct GNUNET_SERVER_Client *client,
+clients_handle_start (void *cls,
+                      struct GNUNET_SERVER_Client *client,
                       const struct GNUNET_MessageHeader *message)
 {
   const struct StartMessage *start;
@@ -507,7 +576,7 @@ clients_handle_start (void *cls, struct GNUNET_SERVER_Client *client,
 
   tc = lookup_client (client);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
               "Client %p sent START\n", tc);
   if (tc != NULL)
   {
@@ -676,7 +745,7 @@ clients_handle_send (void *cls,
     return;
   }
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
-  stcc = GNUNET_malloc (sizeof (struct SendTransmitContinuationContext));
+  stcc = GNUNET_new (struct SendTransmitContinuationContext);
   stcc->target = obm->peer;
   stcc->client = client;
   GNUNET_SERVER_client_keep (client);
@@ -702,11 +771,16 @@ try_connect_if_allowed (void *cls,
 {
   if (GNUNET_OK != result)
   {
-         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                     "Blacklist refuses connection attempt to peer `%s'\n",
-                     GNUNET_i2s (peer));
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Blacklist refuses connection attempt to peer `%s'\n"),
+                GNUNET_i2s (peer));
     return;                     /* not allowed */
   }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              _("Blacklist allows connection attempt to peer `%s'\n"),
+              GNUNET_i2s (peer));
+
   GST_neighbours_try_connect (peer);
 }
 
@@ -719,33 +793,66 @@ try_connect_if_allowed (void *cls,
  * @param message the actual message
  */
 static void
-clients_handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
+clients_handle_request_connect (void *cls,
+                                struct GNUNET_SERVER_Client *client,
                                 const struct GNUNET_MessageHeader *message)
 {
   const struct TransportRequestConnectMessage *trcm =
       (const struct TransportRequestConnectMessage *) message;
 
-  GNUNET_STATISTICS_update (GST_stats,
-                            gettext_noop
-                            ("# REQUEST CONNECT messages received"), 1,
-                            GNUNET_NO);
+  if (GNUNET_YES == ntohl (trcm->connect))
+  {
+    GNUNET_STATISTICS_update (GST_stats,
+                              gettext_noop
+                              ("# REQUEST CONNECT messages received"), 1,
+                              GNUNET_NO);
 
-  if (0 == memcmp (&trcm->peer, &GST_my_identity,
-               sizeof (struct GNUNET_PeerIdentity)))
+    if (0 == memcmp (&trcm->peer, &GST_my_identity,
+                  sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break_op (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Received a request connect message myself `%s'\n",
+                  GNUNET_i2s (&trcm->peer));
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  _("Received a request connect message for peer `%s'\n"),
+                  GNUNET_i2s (&trcm->peer));
+
+      (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed,
+                                       NULL);
+    }
+  }
+  else if (GNUNET_NO == ntohl (trcm->connect))
   {
-       GNUNET_break_op (0);
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Received a request connect message myself `%s'\n",
-                GNUNET_i2s (&trcm->peer));
+    GNUNET_STATISTICS_update (GST_stats,
+                              gettext_noop
+                              ("# REQUEST DISCONNECT messages received"), 1,
+                              GNUNET_NO);
+
+    if (0 == memcmp (&trcm->peer, &GST_my_identity,
+                  sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break_op (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Received a request disconnect message myself `%s'\n",
+                  GNUNET_i2s (&trcm->peer));
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  _("Received a request disconnect message for peer `%s'\n"),
+                  GNUNET_i2s (&trcm->peer));
+      (void) GST_neighbours_force_disconnect (&trcm->peer);
+    }
   }
   else
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Received a request connect message for peer `%s'\n",
-                GNUNET_i2s (&trcm->peer));
-
-    (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed,
-                                     NULL);
+    GNUNET_break_op (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
   }
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
@@ -753,26 +860,78 @@ clients_handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
 
 /**
  * Take the given address and append it to the set of results sent back to
- * the client.
+ * the client.  This function may be called serveral times for a single
+ * conversion.   The last invocation will be with a @a address of
+ * NULL and a @a res of #GNUNET_OK.  Thus, to indicate conversion
+ * errors, the callback might be called first with @a address NULL and
+ * @a res being #GNUNET_SYSERR.  In that case, there will still be a
+ * subsequent call later with @a address NULL and @a res #GNUNET_OK.
  *
- * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
- * @param buf text to transmit
+ * @param cls the transmission context used (`struct GNUNET_SERVER_TransmitContext *`)
+ * @param buf text to transmit (contains the human-readable address, or NULL)
+ * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error,
+ *            never #GNUNET_NO
  */
 static void
-transmit_address_to_client (void *cls, const char *buf)
+transmit_address_to_client (void *cls,
+                            const char *buf,
+                            int res)
 {
   struct AddressToStringContext *actx = cls;
+  struct AddressToStringResultMessage *atsm;
+  size_t len;
+  size_t slen;
+
+  GNUNET_assert ( (GNUNET_OK == res) ||
+                  (GNUNET_SYSERR == res) );
   if (NULL == buf)
   {
-    GNUNET_SERVER_transmit_context_append_data (actx->tc, NULL, 0,
-                                                GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
-    GNUNET_SERVER_transmit_context_run (actx->tc, GNUNET_TIME_UNIT_FOREVER_REL);
-    GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, actx);
-    GNUNET_free (actx);
-    return;
+    len = sizeof (struct AddressToStringResultMessage);
+    atsm = GNUNET_malloc (len);
+    atsm->header.size = ntohs (len);
+    atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+    if (GNUNET_OK == res)
+    {
+      /* this was the last call, transmit */
+      atsm->res = htonl (GNUNET_OK);
+      atsm->addr_len = htonl (0);
+      GNUNET_SERVER_transmit_context_append_message (actx->tc,
+                                                     (const struct GNUNET_MessageHeader *) atsm);
+      GNUNET_SERVER_transmit_context_run (actx->tc,
+                                          GNUNET_TIME_UNIT_FOREVER_REL);
+      GNUNET_CONTAINER_DLL_remove (a2s_head,
+                                   a2s_tail,
+                                   actx);
+      GNUNET_free (atsm);
+      GNUNET_free (actx);
+      return;
+    }
+    if (GNUNET_SYSERR == res)
+    {
+      /* address conversion failed, but there will be more callbacks */
+      atsm->res = htonl (GNUNET_SYSERR);
+      atsm->addr_len = htonl (0);
+      GNUNET_SERVER_transmit_context_append_message (actx->tc,
+                                                     (const struct GNUNET_MessageHeader *) atsm);
+      GNUNET_free (atsm);
+      return;
+    }
   }
-  GNUNET_SERVER_transmit_context_append_data (actx->tc, buf, strlen (buf) + 1,
-                                              GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+  GNUNET_assert (GNUNET_OK == res);
+  /* succesful conversion, append*/
+  slen = strlen (buf) + 1;
+  len = sizeof (struct AddressToStringResultMessage) + slen;
+  atsm = GNUNET_malloc (len);
+  atsm->header.size = ntohs (len);
+  atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+  atsm->res = htonl (GNUNET_YES);
+  atsm->addr_len = htonl (slen);
+  memcpy (&atsm[1],
+          buf,
+          slen);
+  GNUNET_SERVER_transmit_context_append_message (actx->tc,
+                                                 (const struct GNUNET_MessageHeader *) atsm);
+  GNUNET_free (atsm);
 }
 
 
@@ -796,6 +955,7 @@ clients_handle_address_to_string (void *cls,
   uint16_t size;
   struct GNUNET_SERVER_TransmitContext *tc;
   struct AddressToStringContext *actx;
+  struct AddressToStringResultMessage atsm;
   struct GNUNET_TIME_Relative rtimeout;
   int32_t numeric;
 
@@ -816,8 +976,7 @@ clients_handle_address_to_string (void *cls,
   }
   address = (const char *) &alum[1];
   plugin_name = (const char *) &address[address_len];
-  if (plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1]
-      != '\0')
+  if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
   {
     GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
@@ -829,33 +988,47 @@ clients_handle_address_to_string (void *cls,
   papi = GST_plugins_printer_find (plugin_name);
   if (NULL == papi)
   {
-    GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
-                                                GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
-    GNUNET_SERVER_transmit_context_run (tc, rtimeout);
+    atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
+    atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+    atsm.res = htonl (GNUNET_SYSERR);
+    atsm.addr_len = htonl (0);
+    GNUNET_SERVER_transmit_context_append_message (tc,
+                                                   &atsm.header);
+    atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage));
+    atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+    atsm.res = htonl (GNUNET_OK);
+    atsm.addr_len = htonl (0);
+    GNUNET_SERVER_transmit_context_append_message (tc,
+                                                   &atsm.header);
+    GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
     return;
   }
   actx = GNUNET_new (struct AddressToStringContext);
   actx->tc = tc;
   GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
   GNUNET_SERVER_disable_receive_done_warning (client);
-  papi->address_pretty_printer (papi->cls, plugin_name, address, address_len,
-                                numeric, rtimeout, &transmit_address_to_client,
+  papi->address_pretty_printer (papi->cls,
+                                plugin_name,
+                                address, address_len,
+                                numeric,
+                                rtimeout,
+                                &transmit_address_to_client,
                                 actx);
 }
 
 
 /**
- * Compose AddressIterateResponseMessage using the given peer and address.
+ * Compose #PeerIterateResponseMessage using the given peer and address.
  *
  * @param peer identity of the peer
  * @param address the address, NULL on disconnect
  * @return composed message
  */
-static struct AddressIterateResponseMessage *
+static struct PeerIterateResponseMessage *
 compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
                                           const struct GNUNET_HELLO_Address *address)
 {
-  struct AddressIterateResponseMessage *msg;
+  struct PeerIterateResponseMessage *msg;
   size_t size;
   size_t tlen;
   size_t alen;
@@ -869,17 +1042,19 @@ compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer
   }
   else
     tlen = alen = 0;
-  size = (sizeof (struct AddressIterateResponseMessage) + alen + tlen);
+  size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen);
   msg = GNUNET_malloc (size);
   msg->header.size = htons (size);
   msg->header.type =
-      htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE);
+      htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
   msg->reserved = htonl (0);
   msg->peer = *peer;
   msg->addrlen = htonl (alen);
   msg->pluginlen = htonl (tlen);
+
   if (NULL != address)
   {
+    msg->local_address_info = htonl((uint32_t) address->local_info);
     addr = (char *) &msg[1];
     memcpy (addr, address->address, alen);
     memcpy (&addr[alen], address->transport_name, tlen);
@@ -887,34 +1062,144 @@ compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer
   return msg;
 }
 
+/**
+ * Compose #PeerIterateResponseMessage using the given peer and address.
+ *
+ * @param peer identity of the peer
+ * @param address the address, NULL on disconnect
+ * @return composed message
+ */
+static struct ValidationIterateResponseMessage *
+compose_validation_iterate_response_message (const struct GNUNET_PeerIdentity *peer,
+                                          const struct GNUNET_HELLO_Address *address)
+{
+  struct ValidationIterateResponseMessage *msg;
+  size_t size;
+  size_t tlen;
+  size_t alen;
+  char *addr;
+
+  GNUNET_assert (NULL != peer);
+  if (NULL != address)
+  {
+    tlen = strlen (address->transport_name) + 1;
+    alen = address->address_length;
+  }
+  else
+    tlen = alen = 0;
+  size = (sizeof (struct ValidationIterateResponseMessage) + alen + tlen);
+  msg = GNUNET_malloc (size);
+  msg->header.size = htons (size);
+  msg->header.type =
+      htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
+  msg->reserved = htonl (0);
+  msg->peer = *peer;
+  msg->addrlen = htonl (alen);
+  msg->pluginlen = htonl (tlen);
+
+  if (NULL != address)
+  {
+    msg->local_address_info = htonl((uint32_t) address->local_info);
+    addr = (char *) &msg[1];
+    memcpy (addr, address->address, alen);
+    memcpy (&addr[alen], address->transport_name, tlen);
+  }
+  return msg;
+}
+
+struct IterationContext
+{
+  struct GNUNET_SERVER_TransmitContext *tc;
+
+  struct GNUNET_PeerIdentity id;
+
+  int all;
+};
+
+
+/**
+ * Output information of validation entries to the given client.
+ *
+ * @param cls the `struct IterationContext *`
+ * @param peer identity of the neighbour
+ * @param address the address
+ * @param last_validation point in time when last validation was performed
+ * @param valid_until point in time how long address is valid
+ * @param next_validation point in time when next validation will be performed
+ * @param state state of validation notification
+ */
+static void
+send_validation_information (void *cls,
+                             const struct GNUNET_PeerIdentity *peer,
+                             const struct GNUNET_HELLO_Address *address,
+                             struct GNUNET_TIME_Absolute last_validation,
+                             struct GNUNET_TIME_Absolute valid_until,
+                             struct GNUNET_TIME_Absolute next_validation,
+                             enum GNUNET_TRANSPORT_ValidationState state)
+{
+  struct IterationContext *pc = cls;
+  struct ValidationIterateResponseMessage *msg;
+
+  if ( (GNUNET_YES == pc->all) ||
+       (0 == memcmp (peer, &pc->id, sizeof (pc->id))) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Sending information about for validation entry for peer `%s' using address `%s'\n",
+        GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : "<none>");
+    msg = compose_validation_iterate_response_message (peer, address);
+    msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
+    msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
+    msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
+    msg->state = htonl ((uint32_t) state);
+    GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
+    GNUNET_free (msg);
+  }
+}
+
 
 /**
- * Output the active address of connected neighbours to the given client.
+ * Output information of neighbours to the given client.
  *
- * @param cls the 'struct GNUNET_SERVER_TransmitContext' for transmission to the client
+ * @param cls the `struct PeerIterationContext *`
  * @param peer identity of the neighbour
  * @param address the address
+ * @param state current state this peer is in
+ * @param state_timeout timeout for the current state of the peer
  * @param bandwidth_in inbound quota in NBO
  * @param bandwidth_out outbound quota in NBO
  */
 static void
-output_address (void *cls, const struct GNUNET_PeerIdentity *peer,
-                const struct GNUNET_HELLO_Address *address,
-                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
-                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
+send_peer_information (void *cls,
+                       const struct GNUNET_PeerIdentity *peer,
+                       const struct GNUNET_HELLO_Address *address,
+                       enum GNUNET_TRANSPORT_PeerState state,
+                       struct GNUNET_TIME_Absolute state_timeout,
+                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
+                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
 {
-  struct GNUNET_SERVER_TransmitContext *tc = cls;
-  struct AddressIterateResponseMessage *msg;
+  struct IterationContext *pc = cls;
+  struct PeerIterateResponseMessage *msg;
 
-  msg = compose_address_iterate_response_message (peer, address);
-  GNUNET_SERVER_transmit_context_append_message (tc, &msg->header);
-  GNUNET_free (msg);
+  if ( (GNUNET_YES == pc->all) ||
+       (0 == memcmp (peer, &pc->id, sizeof (pc->id))) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Sending information about `%s' using address `%s' in state `%s'\n",
+        GNUNET_i2s(peer),
+        (address != NULL) ? GST_plugins_a2s (address) : "<none>",
+        GNUNET_TRANSPORT_ps2s (state));
+    msg = compose_address_iterate_response_message (peer, address);
+    msg->state = htonl (state);
+    msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout);
+    GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header);
+    GNUNET_free (msg);
+  }
 }
 
 
+
 /**
- * Client asked to obtain information about all actively used addresses
- * of connected peers
+ * Client asked to obtain information about a specific or all peers
  * Process the request.
  *
  * @param cls unused
@@ -922,29 +1207,29 @@ output_address (void *cls, const struct GNUNET_PeerIdentity *peer,
  * @param message the peer address information request
  */
 static void
-clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client,
+clients_handle_monitor_peers (void *cls, struct GNUNET_SERVER_Client *client,
                                 const struct GNUNET_MessageHeader *message)
 {
   static struct GNUNET_PeerIdentity all_zeros;
   struct GNUNET_SERVER_TransmitContext *tc;
-  struct AddressIterateMessage *msg;
-  struct GNUNET_HELLO_Address *address;
+  struct PeerMonitorMessage *msg;
+  struct IterationContext pc;
 
-  if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE)
+  if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST)
   {
     GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  if (ntohs (message->size) != sizeof (struct AddressIterateMessage))
+  if (ntohs (message->size) != sizeof (struct PeerMonitorMessage))
   {
     GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  msg = (struct AddressIterateMessage *) message;
+  msg = (struct PeerMonitorMessage *) message;
   if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
-       (NULL != lookup_monitoring_client (client)) )
+       (NULL != lookup_monitoring_client (peer_monitoring_clients_head, client)) )
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
                "ServerClient %p tried to start monitoring twice\n",
@@ -954,30 +1239,108 @@ clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
   GNUNET_SERVER_disable_receive_done_warning (client);
-  tc = GNUNET_SERVER_transmit_context_create (client);
+  pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
+
+  /* Send initial list */
   if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity)))
   {
     /* iterate over all neighbours */
-    GST_neighbours_iterate (&output_address, tc);
+    pc.all = GNUNET_YES;
+    pc.id = msg->peer;
   }
   else
   {
     /* just return one neighbour */
-    address = GST_neighbour_get_current_address (&msg->peer);
-    if (address != NULL)
-      output_address (tc, &msg->peer, address,
-                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
-                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT);
+    pc.all = GNUNET_NO;
+    pc.id = msg->peer;
   }
+  GST_neighbours_iterate (&send_peer_information, &pc);
+
   if (GNUNET_YES != ntohl (msg->one_shot))
-    setup_monitoring_client (client, &msg->peer);
+  {
+    setup_peer_monitoring_client (client, &msg->peer);
+  }
   else
+  {
     GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
-                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE);
+        GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE);
+  }
+
   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
 
+/**
+ * Client asked to obtain information about a specific or all validation
+ * processes
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the peer address information request
+ */
+static void
+clients_handle_monitor_validation (void *cls, struct GNUNET_SERVER_Client *client,
+                                const struct GNUNET_MessageHeader *message)
+{
+  static struct GNUNET_PeerIdentity all_zeros;
+  struct GNUNET_SERVER_TransmitContext *tc;
+  struct PeerMonitorMessage *msg;
+  struct IterationContext pc;
+
+  if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  if (ntohs (message->size) != sizeof (struct ValidationMonitorMessage))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msg = (struct PeerMonitorMessage *) message;
+  if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
+       (NULL != lookup_monitoring_client (val_monitoring_clients_head, client)) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+                "ServerClient %p tried to start monitoring twice\n",
+                client);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  GNUNET_SERVER_disable_receive_done_warning (client);
+  pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);
+
+  /* Send initial list */
+  if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity)))
+  {
+    /* iterate over all neighbours */
+    pc.all = GNUNET_YES;
+    pc.id = msg->peer;
+  }
+  else
+  {
+    /* just return one neighbour */
+    pc.all = GNUNET_NO;
+    pc.id = msg->peer;
+  }
+
+  GST_validation_iterate (&send_validation_information, &pc);
+
+  if (GNUNET_YES != ntohl (msg->one_shot))
+  {
+    setup_val_monitoring_client (client, &msg->peer);
+  }
+  else
+  {
+    GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+        GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
+  }
+  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
 /**
  * Start handling requests from clients.
  *
@@ -998,9 +1361,12 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server)
      sizeof (struct TransportRequestConnectMessage)},
     {&clients_handle_address_to_string, NULL,
      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
-    {&clients_handle_address_iterate, NULL,
-     GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
-     sizeof (struct AddressIterateMessage)},
+    {&clients_handle_monitor_peers, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
+     sizeof (struct PeerMonitorMessage)},
+    {&clients_handle_monitor_validation, NULL,
+     GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST,
+     sizeof (struct ValidationMonitorMessage)},
     {&GST_blacklist_handle_init, NULL,
      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
      sizeof (struct GNUNET_MessageHeader)},
@@ -1011,7 +1377,8 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server)
      GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC, 0},
     {NULL, NULL, 0, 0}
   };
-  nc = GNUNET_SERVER_notification_context_create (server, 0);
+  peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
+  val_nc = GNUNET_SERVER_notification_context_create (server, 0);
   GNUNET_SERVER_add_handlers (server, handlers);
   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
                                    NULL);
@@ -1032,10 +1399,15 @@ GST_clients_stop ()
     GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
     GNUNET_free (cur);
   }
-  if (NULL != nc)
+  if (NULL != peer_nc)
+  {
+    GNUNET_SERVER_notification_context_destroy (peer_nc);
+    peer_nc = NULL;
+  }
+  if (NULL != val_nc)
   {
-    GNUNET_SERVER_notification_context_destroy (nc);
-    nc = NULL;
+    GNUNET_SERVER_notification_context_destroy (val_nc);
+    val_nc = NULL;
   }
 }
 
@@ -1085,16 +1457,22 @@ GST_clients_unicast (struct GNUNET_SERVER_Client *client,
  *
  * @param peer peer this update is about (never NULL)
  * @param address address, NULL on disconnect
+ * @param state the current state of the peer
+ * @param state_timeout the time out for the state
  */
 void
-GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity *peer,
-                                            const struct GNUNET_HELLO_Address *address)
+GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_HELLO_Address *address,
+    enum GNUNET_TRANSPORT_PeerState state,
+    struct GNUNET_TIME_Absolute state_timeout)
 {
-  struct AddressIterateResponseMessage *msg;
+  struct PeerIterateResponseMessage *msg;
   struct MonitoringClient *mc;
   static struct GNUNET_PeerIdentity all_zeros;
   msg = compose_address_iterate_response_message (peer, address);
-  mc = monitoring_clients_head;
+  msg->state = htonl (state);
+  msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout);
+  mc = peer_monitoring_clients_head;
   while (mc != NULL)
   {
     if ((0 == memcmp (&mc->peer, &all_zeros,
@@ -1102,7 +1480,7 @@ GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity *pe
         (0 == memcmp (&mc->peer, peer,
                       sizeof (struct GNUNET_PeerIdentity))))
     {
-      GNUNET_SERVER_notification_context_unicast (nc, mc->client,
+      GNUNET_SERVER_notification_context_unicast (peer_nc, mc->client,
                                                   &msg->header, GNUNET_NO);
     }
 
@@ -1111,5 +1489,53 @@ GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity *pe
   GNUNET_free (msg);
 }
 
+/**
+ * Broadcast the new validation changes to all clients monitoring the peer.
+ *
+ * @param peer peer this update is about (never NULL)
+ * @param address address, NULL on disconnect
+ * @param last_validation point in time when last validation was performed
+ * @param valid_until point in time how long address is valid
+ * @param next_validation point in time when next validation will be performed
+ * @param state state of validation notification
+ */
+void
+GST_clients_broadcast_validation_notification (const struct GNUNET_PeerIdentity *peer,
+                                               const struct GNUNET_HELLO_Address *address,
+                                               struct GNUNET_TIME_Absolute last_validation,
+                                               struct GNUNET_TIME_Absolute valid_until,
+                                               struct GNUNET_TIME_Absolute next_validation,
+                                               enum GNUNET_TRANSPORT_ValidationState state)
+{
+  struct ValidationIterateResponseMessage *msg;
+  struct MonitoringClient *mc;
+  static struct GNUNET_PeerIdentity all_zeros;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending information about for validation entry for peer `%s' using address `%s'\n",
+              GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : "<none>");
+
+  msg = compose_validation_iterate_response_message (peer, address);
+  msg->last_validation = GNUNET_TIME_absolute_hton(last_validation);
+  msg->valid_until = GNUNET_TIME_absolute_hton(valid_until);
+  msg->next_validation = GNUNET_TIME_absolute_hton(next_validation);
+  msg->state = htonl ((uint32_t) state);
+  mc = val_monitoring_clients_head;
+  while (mc != NULL)
+  {
+    if ((0 == memcmp (&mc->peer, &all_zeros,
+                      sizeof (struct GNUNET_PeerIdentity))) ||
+        (0 == memcmp (&mc->peer, peer,
+                      sizeof (struct GNUNET_PeerIdentity))))
+    {
+      GNUNET_SERVER_notification_context_unicast (val_nc, mc->client,
+                                                  &msg->header, GNUNET_NO);
+
+    }
+    mc = mc->next;
+  }
+  GNUNET_free (msg);
+}
+
 
 /* end of file gnunet-service-transport_clients.c */