malloc -> new
[oweals/gnunet.git] / src / statistics / statistics_api.c
index f1a22c22a405d4e9a783673d3a316f7b0606f1dd..04e85a07e95323b65d2026990c05d66c836e306b 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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 2, or (at your
+     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
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
  * @author Christian Grothoff
  */
 #include "platform.h"
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_client_lib.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_constants.h"
 #include "gnunet_constants.h"
-#include "gnunet_container_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_protocols.h"
-#include "gnunet_server_lib.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_statistics_service.h"
-#include "gnunet_strings_lib.h"
 #include "statistics.h"
 
 /**
 #include "statistics.h"
 
 /**
@@ -235,6 +232,16 @@ struct GNUNET_STATISTICS_Handle
    */
   struct GNUNET_TIME_Relative backoff;
 
    */
   struct GNUNET_TIME_Relative backoff;
 
+  /**
+   * Maximum heap size observed so far (if available).
+   */
+  uint64_t peak_heap_size;
+
+  /**
+   * Maximum resident set side observed so far (if available).
+   */
+  uint64_t peak_rss;
+
   /**
    * Size of the 'watches' array.
    */
   /**
    * Size of the 'watches' array.
    */
@@ -254,6 +261,51 @@ struct GNUNET_STATISTICS_Handle
 };
 
 
 };
 
 
+/**
+ * Obtain statistics about this process's memory consumption and
+ * report those as well (if they changed).
+ */
+static void
+update_memory_statistics (struct GNUNET_STATISTICS_Handle *h)
+{
+#if ENABLE_HEAP_STATISTICS
+  uint64_t current_heap_size = 0;
+  uint64_t current_rss = 0;
+
+  if (GNUNET_NO != h->do_destroy)
+    return;
+#if HAVE_MALLINFO
+  {
+    struct mallinfo mi;
+
+    mi = mallinfo();
+    current_heap_size = mi.uordblks + mi.fordblks;
+  }
+#endif
+#if HAVE_GETRUSAGE
+  {
+    struct rusage ru;
+
+    if (0 == getrusage (RUSAGE_SELF, &ru))
+    {
+      current_rss = 1024LL * ru.ru_maxrss;
+    }
+  }
+#endif
+  if (current_heap_size > h->peak_heap_size)
+  {
+    h->peak_heap_size = current_heap_size;
+    GNUNET_STATISTICS_set (h, "# peak heap size", current_heap_size, GNUNET_NO);
+  }
+  if (current_rss > h->peak_rss)
+  {
+    h->peak_rss = current_rss;
+    GNUNET_STATISTICS_set (h, "# peak resident set size", current_rss, GNUNET_NO);
+  }
+#endif
+}
+
+
 /**
  * Schedule the next action to be performed.
  *
 /**
  * Schedule the next action to be performed.
  *
@@ -280,8 +332,8 @@ schedule_watch_request (struct GNUNET_STATISTICS_Handle *h,
   size_t nlen;
   size_t nsize;
 
   size_t nlen;
   size_t nsize;
 
-  GNUNET_assert (h != NULL);
-  GNUNET_assert (watch != NULL);
+  GNUNET_assert (NULL != h);
+  GNUNET_assert (NULL != watch);
 
   slen = strlen (watch->subsystem) + 1;
   nlen = strlen (watch->name) + 1;
 
   slen = strlen (watch->subsystem) + 1;
   nlen = strlen (watch->name) + 1;
@@ -291,7 +343,7 @@ schedule_watch_request (struct GNUNET_STATISTICS_Handle *h,
     GNUNET_break (0);
     return;
   }
     GNUNET_break (0);
     return;
   }
-  ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
+  ai = GNUNET_new (struct GNUNET_STATISTICS_GetHandle);
   ai->sh = h;
   ai->subsystem = GNUNET_strdup (watch->subsystem);
   ai->name = GNUNET_strdup (watch->name);
   ai->sh = h;
   ai->subsystem = GNUNET_strdup (watch->subsystem);
   ai->name = GNUNET_strdup (watch->name);
@@ -329,25 +381,26 @@ static void
 do_disconnect (struct GNUNET_STATISTICS_Handle *h)
 {
   struct GNUNET_STATISTICS_GetHandle *c;
 do_disconnect (struct GNUNET_STATISTICS_Handle *h)
 {
   struct GNUNET_STATISTICS_GetHandle *c;
-  
+
   if (NULL != h->th)
   {
     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
     h->th = NULL;
   if (NULL != h->th)
   {
     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
     h->th = NULL;
-  } 
-  if (NULL != h->client)
-  {
-    GNUNET_CLIENT_disconnect (h->client);
-    h->client = NULL;
   }
   h->receiving = GNUNET_NO;
   if (NULL != (c = h->current))
   {
     h->current = NULL;
   }
   h->receiving = GNUNET_NO;
   if (NULL != (c = h->current))
   {
     h->current = NULL;
-    if (c->cont != NULL)
+    if ( (NULL != c->cont) &&
+        (GNUNET_YES != c->aborted) )
       c->cont (c->cls, GNUNET_SYSERR);
     free_action_item (c);
   }
       c->cont (c->cls, GNUNET_SYSERR);
     free_action_item (c);
   }
+  if (NULL != h->client)
+  {
+    GNUNET_CLIENT_disconnect (h->client);
+    h->client = NULL;
+  }
 }
 
 
 }
 
 
@@ -355,7 +408,7 @@ do_disconnect (struct GNUNET_STATISTICS_Handle *h)
  * Try to (re)connect to the statistics service.
  *
  * @param h statistics handle to reconnect
  * Try to (re)connect to the statistics service.
  *
  * @param h statistics handle to reconnect
- * @return GNUNET_YES on success, GNUNET_NO on failure.
+ * @return #GNUNET_YES on success, #GNUNET_NO on failure.
  */
 static int
 try_connect (struct GNUNET_STATISTICS_Handle *h)
  */
 static int
 try_connect (struct GNUNET_STATISTICS_Handle *h)
@@ -364,14 +417,14 @@ try_connect (struct GNUNET_STATISTICS_Handle *h)
   struct GNUNET_STATISTICS_GetHandle *gn;
   unsigned int i;
 
   struct GNUNET_STATISTICS_GetHandle *gn;
   unsigned int i;
 
-  if (h->backoff_task != GNUNET_SCHEDULER_NO_TASK)
+  if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task)
     return GNUNET_NO;
     return GNUNET_NO;
-  if (h->client != NULL)
+  if (NULL != h->client)
     return GNUNET_YES;
     return GNUNET_YES;
-  h->client = GNUNET_CLIENT_connect ("statistics", h->cfg);  
-  if (h->client != NULL)
+  h->client = GNUNET_CLIENT_connect ("statistics", h->cfg);
+  if (NULL != h->client)
   {
   {
-    gn = h->action_head; 
+    gn = h->action_head;
     while (NULL != (gh = gn))
     {
       gn = gh->next;
     while (NULL != (gh = gn))
     {
       gn = gh->next;
@@ -380,7 +433,7 @@ try_connect (struct GNUNET_STATISTICS_Handle *h)
        GNUNET_CONTAINER_DLL_remove (h->action_head,
                                     h->action_tail,
                                     gh);
        GNUNET_CONTAINER_DLL_remove (h->action_head,
                                     h->action_tail,
                                     gh);
-       free_action_item (gh);  
+       free_action_item (gh);
       }
     }
     for (i = 0; i < h->watches_size; i++)
       }
     }
     for (i = 0; i < h->watches_size; i++)
@@ -412,6 +465,22 @@ reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 }
 
 
 }
 
 
+/**
+ * Task used by 'reconnect_later' to shutdown the handle
+ *
+ * @param cls the statistics handle
+ * @param tc scheduler context
+ */
+static void
+do_destroy (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_STATISTICS_Handle *h = cls;
+
+  GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+}
+
+
 /**
  * Reconnect at a later time, respecting back-off.
  *
 /**
  * Reconnect at a later time, respecting back-off.
  *
@@ -420,24 +489,32 @@ reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 static void
 reconnect_later (struct GNUNET_STATISTICS_Handle *h)
 {
 static void
 reconnect_later (struct GNUNET_STATISTICS_Handle *h)
 {
+  int loss;
+  struct GNUNET_STATISTICS_GetHandle *gh;
+
   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->backoff_task);
   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->backoff_task);
-  if (h->do_destroy)
+  if (GNUNET_YES == h->do_destroy)
   {
     /* So we are shutting down and the service is not reachable.
      * Chances are that it's down for good and we are not going to connect to
      * it anymore.
      * Give up and don't sync the rest of the data.
      */
   {
     /* So we are shutting down and the service is not reachable.
      * Chances are that it's down for good and we are not going to connect to
      * it anymore.
      * Give up and don't sync the rest of the data.
      */
-    GNUNET_break (0);
+    loss = GNUNET_NO;
+    for (gh = h->action_head; NULL != gh; gh = gh->next)
+      if ( (gh->make_persistent) && (ACTION_SET == gh->type) )
+       loss = GNUNET_YES;
+    if (GNUNET_YES == loss)
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                 _("Could not save some persistent statistics\n"));
     h->do_destroy = GNUNET_NO;
     h->do_destroy = GNUNET_NO;
-    GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+    GNUNET_SCHEDULER_add_continuation (&do_destroy, h,
+                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
     return;
   }
   h->backoff_task =
     GNUNET_SCHEDULER_add_delayed (h->backoff, &reconnect_task, h);
     return;
   }
   h->backoff_task =
     GNUNET_SCHEDULER_add_delayed (h->backoff, &reconnect_task, h);
-  h->backoff = GNUNET_TIME_relative_multiply (h->backoff, 2);
-  h->backoff =
-    GNUNET_TIME_relative_min (h->backoff, GNUNET_CONSTANTS_SERVICE_TIMEOUT);
+  h->backoff = GNUNET_TIME_STD_BACKOFF (h->backoff);
 }
 
 
 }
 
 
@@ -524,8 +601,8 @@ process_watch_value (struct GNUNET_STATISTICS_Handle *h,
     return GNUNET_SYSERR;
   }
   w = h->watches[wid];
     return GNUNET_SYSERR;
   }
   w = h->watches[wid];
-  if (NULL == w)  
-    return GNUNET_NO;  
+  if (NULL == w)
+    return GNUNET_NO;
   (void) w->proc (w->proc_cls, w->subsystem, w->name,
                   GNUNET_ntohll (wvm->value),
                   0 != (ntohl (wvm->flags) & GNUNET_STATISTICS_PERSIST_BIT));
   (void) w->proc (w->proc_cls, w->subsystem, w->name,
                   GNUNET_ntohll (wvm->value),
                   0 != (ntohl (wvm->flags) & GNUNET_STATISTICS_PERSIST_BIT));
@@ -533,6 +610,16 @@ process_watch_value (struct GNUNET_STATISTICS_Handle *h,
 }
 
 
 }
 
 
+static void
+destroy_task (void *cls,
+             const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_STATISTICS_Handle *h = cls;
+
+  GNUNET_STATISTICS_destroy (h, GNUNET_NO);
+}
+
+
 /**
  * Function called with messages from stats service.
  *
 /**
  * Function called with messages from stats service.
  *
@@ -546,7 +633,7 @@ receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
   struct GNUNET_STATISTICS_GetHandle *c;
   int ret;
 
   struct GNUNET_STATISTICS_GetHandle *c;
   int ret;
 
-  if (msg == NULL)
+  if (NULL == msg)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
          "Error receiving statistics from service, is the service running?\n");
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
          "Error receiving statistics from service, is the service running?\n");
@@ -556,6 +643,19 @@ receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
   }
   switch (ntohs (msg->type))
   {
   }
   switch (ntohs (msg->type))
   {
+  case GNUNET_MESSAGE_TYPE_TEST:
+    if (GNUNET_SYSERR != h->do_destroy)
+    {
+      /* not in shutdown, why do we get 'TEST'? */
+      GNUNET_break (0);
+      do_disconnect (h);
+      reconnect_later (h);
+      return;
+    }
+    h->do_destroy = GNUNET_NO;
+    GNUNET_SCHEDULER_add_continuation (&destroy_task, h,
+                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+    break;
   case GNUNET_MESSAGE_TYPE_STATISTICS_END:
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of statistics marker\n");
     if (NULL == (c = h->current))
   case GNUNET_MESSAGE_TYPE_STATISTICS_END:
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of statistics marker\n");
     if (NULL == (c = h->current))
@@ -574,10 +674,10 @@ receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
     else
     {
       h->receiving = GNUNET_NO;
     else
     {
       h->receiving = GNUNET_NO;
-    }    
+    }
     h->current = NULL;
     schedule_action (h);
     h->current = NULL;
     schedule_action (h);
-    if (c->cont != NULL)
+    if (NULL != c->cont)
       c->cont (c->cls, GNUNET_OK);
     free_action_item (c);
     return;
       c->cont (c->cls, GNUNET_OK);
     free_action_item (c);
     return;
@@ -586,7 +686,7 @@ receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
     {
       do_disconnect (h);
       reconnect_later (h);
     {
       do_disconnect (h);
       reconnect_later (h);
-      return;     
+      return;
     }
     /* finally, look for more! */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
     }
     /* finally, look for more! */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -597,12 +697,12 @@ receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
     h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
     return;
   case GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE:
     h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
     return;
   case GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE:
-    if (GNUNET_OK != 
+    if (GNUNET_OK !=
        (ret = process_watch_value (h, msg)))
     {
       do_disconnect (h);
       if (GNUNET_NO == ret)
        (ret = process_watch_value (h, msg)))
     {
       do_disconnect (h);
       if (GNUNET_NO == ret)
-       h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; 
+       h->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
       reconnect_later (h);
       return;
     }
       reconnect_later (h);
       return;
     }
@@ -610,7 +710,7 @@ receive_stats (void *cls, const struct GNUNET_MessageHeader *msg)
     GNUNET_assert (h->watches_size > 0);
     GNUNET_CLIENT_receive (h->client, &receive_stats, h,
                           GNUNET_TIME_UNIT_FOREVER_REL);
     GNUNET_assert (h->watches_size > 0);
     GNUNET_CLIENT_receive (h->client, &receive_stats, h,
                           GNUNET_TIME_UNIT_FOREVER_REL);
-    return;    
+    return;
   default:
     GNUNET_break (0);
     do_disconnect (h);
   default:
     GNUNET_break (0);
     do_disconnect (h);
@@ -639,7 +739,7 @@ transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
   uint16_t msize;
 
   GNUNET_assert (NULL != (c = handle->current));
   uint16_t msize;
 
   GNUNET_assert (NULL != (c = handle->current));
-  if (buf == NULL)
+  if (NULL == buf)
   {
     /* timeout / error */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
   {
     /* timeout / error */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -688,7 +788,7 @@ transmit_watch (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
   size_t slen2;
   uint16_t msize;
 
   size_t slen2;
   uint16_t msize;
 
-  if (buf == NULL)
+  if (NULL == buf)
   {
     /* timeout / error */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
   {
     /* timeout / error */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -771,6 +871,7 @@ transmit_set (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf)
   GNUNET_assert (NULL == handle->current->cont);
   free_action_item (handle->current);
   handle->current = NULL;
   GNUNET_assert (NULL == handle->current->cont);
   free_action_item (handle->current);
   handle->current = NULL;
+  update_memory_statistics (handle);
   return nsize;
 }
 
   return nsize;
 }
 
@@ -826,9 +927,12 @@ GNUNET_STATISTICS_create (const char *subsystem,
 {
   struct GNUNET_STATISTICS_Handle *ret;
 
 {
   struct GNUNET_STATISTICS_Handle *ret;
 
-  GNUNET_assert (subsystem != NULL);
-  GNUNET_assert (cfg != NULL);
-  ret = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_Handle));
+  if (GNUNET_YES ==
+      GNUNET_CONFIGURATION_get_value_yesno (cfg, "statistics", "DISABLE"))
+    return NULL;
+  GNUNET_assert (NULL != subsystem);
+  GNUNET_assert (NULL != cfg);
+  ret = GNUNET_new (struct GNUNET_STATISTICS_Handle);
   ret->cfg = cfg;
   ret->subsystem = GNUNET_strdup (subsystem);
   ret->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
   ret->cfg = cfg;
   ret->subsystem = GNUNET_strdup (subsystem);
   ret->backoff = GNUNET_TIME_UNIT_MILLISECONDS;
@@ -852,7 +956,7 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
   struct GNUNET_TIME_Relative timeout;
   int i;
 
   struct GNUNET_TIME_Relative timeout;
   int i;
 
-  if (h == NULL)
+  if (NULL == h)
     return;
   GNUNET_assert (GNUNET_NO == h->do_destroy); // Don't call twice.
   if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task)
     return;
   GNUNET_assert (GNUNET_NO == h->do_destroy); // Don't call twice.
   if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task)
@@ -862,9 +966,9 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
   }
   if (sync_first)
   {
   }
   if (sync_first)
   {
-    if (h->current != NULL)
+    if (NULL != h->current)
     {
     {
-      if (h->current->type == ACTION_GET)
+      if (ACTION_GET == h->current->type)
       {
         GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
         h->th = NULL;
       {
         GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
         h->th = NULL;
@@ -872,11 +976,11 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
         h->current = NULL;
       }
     }
         h->current = NULL;
       }
     }
-    next = h->action_head; 
+    next = h->action_head;
     while (NULL != (pos = next))
     {
       next = pos->next;
     while (NULL != (pos = next))
     {
       next = pos->next;
-      if (pos->type == ACTION_GET)
+      if (ACTION_GET == pos->type)
       {
        GNUNET_CONTAINER_DLL_remove (h->action_head,
                                     h->action_tail,
       {
        GNUNET_CONTAINER_DLL_remove (h->action_head,
                                     h->action_tail,
@@ -890,24 +994,17 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
                                   h->action_tail,
                                   h->current);
     h->do_destroy = GNUNET_YES;
                                   h->action_tail,
                                   h->current);
     h->do_destroy = GNUNET_YES;
-    if ((h->current != NULL) && (h->th == NULL))
+    if ((NULL != h->current) && (NULL == h->th) &&
+       (NULL != h->client))
     {
     {
-      if (NULL == h->client)
-      {
-       /* instant-connect (regardless of back-off) to submit final value */
-       h->client = GNUNET_CLIENT_connect ("statistics", h->cfg);
-      }
-      if (NULL != h->client)
-      {
-       timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout);
-       h->th =
-          GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize,
-                                               timeout, GNUNET_YES,
-                                               &transmit_action, h);
-       GNUNET_assert (NULL != h->th);
-      }
+      timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout);
+      h->th =
+       GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize,
+                                            timeout, GNUNET_YES,
+                                            &transmit_action, h);
+      GNUNET_assert (NULL != h->th);
     }
     }
-    if (h->th != NULL)
+    if (NULL != h->th)
       return; /* do not finish destruction just yet */
   }
   while (NULL != (pos = h->action_head))
       return; /* do not finish destruction just yet */
   }
   while (NULL != (pos = h->action_head))
@@ -921,7 +1018,7 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
   for (i = 0; i < h->watches_size; i++)
   {
     if (NULL == h->watches[i])
   for (i = 0; i < h->watches_size; i++)
   {
     if (NULL == h->watches[i])
-      continue; 
+      continue;
     GNUNET_free (h->watches[i]->subsystem);
     GNUNET_free (h->watches[i]->name);
     GNUNET_free (h->watches[i]);
     GNUNET_free (h->watches[i]->subsystem);
     GNUNET_free (h->watches[i]->name);
     GNUNET_free (h->watches[i]);
@@ -932,6 +1029,47 @@ GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first)
 }
 
 
 }
 
 
+/**
+ * Function called to transmit TEST message to service to
+ * confirm that the service has received all of our 'SET'
+ * messages (during statistics disconnect/shutdown).
+ *
+ * @param cls the 'struct GNUNET_STATISTICS_Handle'
+ * @param size how many bytes can we write to buf
+ * @param buf where to write requests to the service
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_test_on_shutdown (void *cls,
+                          size_t size,
+                          void *buf)
+{
+  struct GNUNET_STATISTICS_Handle *h = cls;
+  struct GNUNET_MessageHeader hdr;
+
+  h->th = NULL;
+  if (NULL == buf)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               _("Failed to receive acknowledgement from statistics service, some statistics might have been lost!\n"));
+    h->do_destroy = GNUNET_NO;
+    GNUNET_SCHEDULER_add_continuation (&destroy_task, h,
+                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+    return 0;
+  }
+  hdr.type = htons (GNUNET_MESSAGE_TYPE_TEST);
+  hdr.size = htons (sizeof (struct GNUNET_MessageHeader));
+  memcpy (buf, &hdr, sizeof (hdr));
+  if (GNUNET_YES != h->receiving)
+  {
+    h->receiving = GNUNET_YES;
+    GNUNET_CLIENT_receive (h->client, &receive_stats, h,
+                           GNUNET_TIME_UNIT_FOREVER_REL);
+  }
+  return sizeof (struct GNUNET_MessageHeader);
+}
+
+
 /**
  * Schedule the next action to be performed.
  *
 /**
  * Schedule the next action to be performed.
  *
@@ -942,8 +1080,8 @@ schedule_action (struct GNUNET_STATISTICS_Handle *h)
 {
   struct GNUNET_TIME_Relative timeout;
 
 {
   struct GNUNET_TIME_Relative timeout;
 
-  if ( (h->th != NULL) ||
-       (h->backoff_task != GNUNET_SCHEDULER_NO_TASK) )
+  if ( (NULL != h->th) ||
+       (GNUNET_SCHEDULER_NO_TASK != h->backoff_task) )
     return;                     /* action already pending */
   if (GNUNET_YES != try_connect (h))
   {
     return;                     /* action already pending */
   if (GNUNET_YES != try_connect (h))
   {
@@ -956,10 +1094,14 @@ schedule_action (struct GNUNET_STATISTICS_Handle *h)
   h->current = h->action_head;
   if (NULL == h->current)
   {
   h->current = h->action_head;
   if (NULL == h->current)
   {
-    if (h->do_destroy)
+    if (GNUNET_YES == h->do_destroy)
     {
     {
-      h->do_destroy = GNUNET_NO;
-      GNUNET_STATISTICS_destroy (h, GNUNET_YES);
+      h->do_destroy = GNUNET_SYSERR; /* in 'TEST' mode */
+      h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
+                                                  sizeof (struct GNUNET_MessageHeader),
+                                                  SET_TRANSMIT_TIMEOUT,
+                                                  GNUNET_NO,
+                                                  &transmit_test_on_shutdown, h);
     }
     return;
   }
     }
     return;
   }
@@ -988,6 +1130,7 @@ schedule_action (struct GNUNET_STATISTICS_Handle *h)
  * @param timeout after how long should we give up (and call
  *        cont with an error code)?
  * @param cont continuation to call when done (can be NULL)
  * @param timeout after how long should we give up (and call
  *        cont with an error code)?
  * @param cont continuation to call when done (can be NULL)
+ *        This callback CANNOT destroy the statistics handle in the same call.
  * @param proc function to call on each value
  * @param cls closure for cont and proc
  * @return NULL on error
  * @param proc function to call on each value
  * @param cls closure for cont and proc
  * @return NULL on error
@@ -1005,17 +1148,17 @@ GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle,
 
   if (NULL == handle)
     return NULL;
 
   if (NULL == handle)
     return NULL;
-  GNUNET_assert (proc != NULL);
+  GNUNET_assert (NULL != proc);
   GNUNET_assert (GNUNET_NO == handle->do_destroy);
   GNUNET_assert (GNUNET_NO == handle->do_destroy);
-  if (subsystem == NULL)
+  if (NULL == subsystem)
     subsystem = "";
     subsystem = "";
-  if (name == NULL)
+  if (NULL == name)
     name = "";
   slen1 = strlen (subsystem) + 1;
   slen2 = strlen (name) + 1;
   GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) <
                  GNUNET_SERVER_MAX_MESSAGE_SIZE);
     name = "";
   slen1 = strlen (subsystem) + 1;
   slen2 = strlen (name) + 1;
   GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) <
                  GNUNET_SERVER_MAX_MESSAGE_SIZE);
-  ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
+  ai = GNUNET_new (struct GNUNET_STATISTICS_GetHandle);
   ai->sh = handle;
   ai->subsystem = GNUNET_strdup (subsystem);
   ai->name = GNUNET_strdup (name);
   ai->sh = handle;
   ai->subsystem = GNUNET_strdup (subsystem);
   ai->name = GNUNET_strdup (name);
@@ -1043,6 +1186,7 @@ GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh)
 {
   if (NULL == gh)
     return;
 {
   if (NULL == gh)
     return;
+  gh->cont = NULL;
   if (gh->sh->current == gh)
   {
     gh->aborted = GNUNET_YES;
   if (gh->sh->current == gh)
   {
     gh->aborted = GNUNET_YES;
@@ -1074,9 +1218,9 @@ GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle,
 {
   struct GNUNET_STATISTICS_WatchEntry *w;
 
 {
   struct GNUNET_STATISTICS_WatchEntry *w;
 
-  if (handle == NULL)
+  if (NULL == handle)
     return GNUNET_SYSERR;
     return GNUNET_SYSERR;
-  w = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_WatchEntry));
+  w = GNUNET_new (struct GNUNET_STATISTICS_WatchEntry);
   w->subsystem = GNUNET_strdup (subsystem);
   w->name = GNUNET_strdup (name);
   w->proc = proc;
   w->subsystem = GNUNET_strdup (subsystem);
   w->name = GNUNET_strdup (name);
   w->proc = proc;
@@ -1088,7 +1232,7 @@ GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle,
 
 
 /**
 
 
 /**
- * Stop watching statistics from the peer.  
+ * Stop watching statistics from the peer.
  *
  * @param handle identification of the statistics service
  * @param subsystem limit to the specified subsystem, never NULL
  *
  * @param handle identification of the statistics service
  * @param subsystem limit to the specified subsystem, never NULL
@@ -1105,11 +1249,13 @@ GNUNET_STATISTICS_watch_cancel (struct GNUNET_STATISTICS_Handle *handle,
   struct GNUNET_STATISTICS_WatchEntry *w;
   unsigned int i;
 
   struct GNUNET_STATISTICS_WatchEntry *w;
   unsigned int i;
 
-  if (handle == NULL)
+  if (NULL == handle)
     return GNUNET_SYSERR;
   for (i=0;i<handle->watches_size;i++)
   {
     w = handle->watches[i];
     return GNUNET_SYSERR;
   for (i=0;i<handle->watches_size;i++)
   {
     w = handle->watches[i];
+    if (NULL == w)
+      continue;
     if ( (w->proc == proc) &&
         (w->proc_cls == proc_cls) &&
         (0 == strcmp (w->name, name)) &&
     if ( (w->proc == proc) &&
         (w->proc_cls == proc_cls) &&
         (0 == strcmp (w->name, name)) &&
@@ -1118,9 +1264,9 @@ GNUNET_STATISTICS_watch_cancel (struct GNUNET_STATISTICS_Handle *handle,
       GNUNET_free (w->name);
       GNUNET_free (w->subsystem);
       GNUNET_free (w);
       GNUNET_free (w->name);
       GNUNET_free (w->subsystem);
       GNUNET_free (w);
-      handle->watches[i] = NULL;      
+      handle->watches[i] = NULL;
       return GNUNET_OK;
       return GNUNET_OK;
-    }   
+    }
   }
   return GNUNET_SYSERR;
 }
   }
   return GNUNET_SYSERR;
 }
@@ -1146,8 +1292,8 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name,
   size_t nsize;
   int64_t delta;
 
   size_t nsize;
   int64_t delta;
 
-  GNUNET_assert (h != NULL);
-  GNUNET_assert (name != NULL);
+  GNUNET_assert (NULL != h);
+  GNUNET_assert (NULL != name);
   slen = strlen (h->subsystem) + 1;
   nlen = strlen (name) + 1;
   nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
   slen = strlen (h->subsystem) + 1;
   nlen = strlen (name) + 1;
   nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
@@ -1156,16 +1302,16 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name,
     GNUNET_break (0);
     return;
   }
     GNUNET_break (0);
     return;
   }
-  for (ai = h->action_head; ai != NULL; ai = ai->next)
+  for (ai = h->action_head; NULL != ai; ai = ai->next)
   {
     if (! ( (0 == strcmp (ai->subsystem, h->subsystem)) &&
   {
     if (! ( (0 == strcmp (ai->subsystem, h->subsystem)) &&
-           (0 == strcmp (ai->name, name)) && 
-           ( (ai->type == ACTION_UPDATE) ||
-             (ai->type == ACTION_SET) ) ) )
+           (0 == strcmp (ai->name, name)) &&
+           ( (ACTION_UPDATE == ai->type) ||
+             (ACTION_SET == ai->type) ) ) )
       continue;
       continue;
-    if (ai->type == ACTION_SET)
+    if (ACTION_SET == ai->type)
     {
     {
-      if (type == ACTION_UPDATE)
+      if (ACTION_UPDATE == type)
       {
        delta = (int64_t) value;
        if (delta > 0)
       {
        delta = (int64_t) value;
        if (delta > 0)
@@ -1190,7 +1336,7 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name,
     }
     else
     {
     }
     else
     {
-      if (type == ACTION_UPDATE)
+      if (ACTION_UPDATE == type)
       {
        /* make delta cummulative */
        delta = (int64_t) value;
       {
        /* make delta cummulative */
        delta = (int64_t) value;
@@ -1205,10 +1351,10 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name,
     }
     ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT);
     ai->make_persistent = make_persistent;
     }
     ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT);
     ai->make_persistent = make_persistent;
-    return;  
+    return;
   }
   /* no existing entry matches, create a fresh one */
   }
   /* no existing entry matches, create a fresh one */
-  ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle));
+  ai = GNUNET_new (struct GNUNET_STATISTICS_GetHandle);
   ai->sh = h;
   ai->subsystem = GNUNET_strdup (h->subsystem);
   ai->name = GNUNET_strdup (name);
   ai->sh = h;
   ai->subsystem = GNUNET_strdup (h->subsystem);
   ai->name = GNUNET_strdup (name);
@@ -1236,7 +1382,7 @@ void
 GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle,
                        const char *name, uint64_t value, int make_persistent)
 {
 GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle,
                        const char *name, uint64_t value, int make_persistent)
 {
-  if (handle == NULL)
+  if (NULL == handle)
     return;
   GNUNET_assert (GNUNET_NO == handle->do_destroy);
   add_setter_action (handle, name, make_persistent, value, ACTION_SET);
     return;
   GNUNET_assert (GNUNET_NO == handle->do_destroy);
   add_setter_action (handle, name, make_persistent, value, ACTION_SET);
@@ -1256,9 +1402,9 @@ void
 GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle,
                           const char *name, int64_t delta, int make_persistent)
 {
 GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle,
                           const char *name, int64_t delta, int make_persistent)
 {
-  if (handle == NULL)
+  if (NULL == handle)
     return;
     return;
-  if (delta == 0)
+  if (0 == delta)
     return;
   GNUNET_assert (GNUNET_NO == handle->do_destroy);
   add_setter_action (handle, name, make_persistent, (uint64_t) delta,
     return;
   GNUNET_assert (GNUNET_NO == handle->do_destroy);
   add_setter_action (handle, name, make_persistent, (uint64_t) delta,