Browse Source

Import RPS

Bart Polot 9 years ago
parent
commit
6cd1fc3aa2

+ 12 - 0
.gitignore

@@ -132,6 +132,7 @@
 /pkgconfig/gnunetats.pc
 /pkgconfig/gnunetregex.pc
 /pkgconfig/gnunetnse.pc
+/pkgconfig/gnunetrps.pc
 /pkgconfig/gnunetnat.pc
 /pkgconfig/Makefile.in
 /pkgconfig/Makefile
@@ -1000,6 +1001,17 @@
 /src/revocation/Makefile
 /src/revocation/.deps
 
+# /src/rps/
+/src/rps/rps.conf
+/src/rps/test_rps_multipeer
+/src/rps/Makefile.in
+/src/rps/Makefile
+/src/rps/.deps
+/src/rps/gnunet-service-rps
+/src/rps/gnunet-rps
+/src/rps/*log
+/src/rps/*.trs
+
 # /src/scalarproduct/
 /src/scalarproduct/gnunet-service-scalarproduct
 /src/scalarproduct/scalarproduct.conf

+ 3 - 0
configure.ac

@@ -1483,6 +1483,8 @@ src/regex/Makefile
 src/regex/regex.conf
 src/revocation/Makefile
 src/revocation/revocation.conf
+src/rps/Makefile
+src/rps/rps.conf
 src/secretsharing/Makefile
 src/secretsharing/secretsharing.conf
 src/sensor/Makefile
@@ -1542,6 +1544,7 @@ pkgconfig/gnunetpsyc.pc
 pkgconfig/gnunetpsycstore.pc
 pkgconfig/gnunetregex.pc
 pkgconfig/gnunetrevocation.pc
+pkgconfig/gnunetrps.pc
 pkgconfig/gnunetscalarproduct.pc
 pkgconfig/gnunetset.pc
 pkgconfig/gnunetsocial.pc

+ 2 - 0
pkgconfig/Makefile.am

@@ -31,6 +31,7 @@ pcfiles = \
        gnunetpsycstore.pc \
        gnunetregex.pc \
        gnunetrevocation.pc \
+       gnunetrps.pc \
        gnunetscalarproduct.pc \
        gnunetset.pc \
        gnunetspeaker.pc \
@@ -87,6 +88,7 @@ EXTRA_DIST = \
        gnunetpsycstore.pc.in \
        gnunetregex.pc.in \
        gnunetrevocation.pc.in \
+       gnunetrps.pc.in \
        gnunetscalarproduct.pc.in \
        gnunetset.pc.in \
        gnunetspeaker.pc.in \

+ 12 - 0
pkgconfig/gnunetrps.pc.in

@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GNUnet RPS
+Description: random peer sampling based on the BRAHMS protocol
+URL: https://gnunet.org
+Version: @VERSION@
+Requires:
+Libs: -L${libdir} -lgnunetrps
+Cflags: -I${includedir}

+ 1 - 0
src/Makefile.am

@@ -20,6 +20,7 @@ if HAVE_EXPERIMENTAL
   env \
   psycstore \
   psyc \
+  rps \
   social \
   $(CONSENSUS) \
   $(SECRETSHARING) \

+ 38 - 1
src/include/gnunet_protocols.h

@@ -2630,10 +2630,47 @@ extern "C"
 #define GNUNET_MESSAGE_TYPE_DHT_CLIENT_ACT_MALICIOUS_OK  894
 
 #endif
+
+/*******************************************************************************
+ * RPS messages
+ ******************************************************************************/
+
+/* P2P Messages */
+
+/**
+ * RPS PUSH message to push own ID to another peer
+ */
+#define GNUNET_MESSAGE_TYPE_RPS_PP_PUSH         950
+
+/**
+ * RPS PULL REQUEST message to request the local view of another peer
+ */
+#define GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST 951
+
+/**
+ * RPS PULL REPLY message which contains the view of the other peer
+ */
+#define GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY   952
+
+
+
+/* Client-Service Messages */
+
+/**
+ * RPS CS REQUEST Message for the Client to request (a) random peer(s)
+ */
+#define GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST      953
+
+/**
+ * RPS CS REPLY Message for the Server to send (a) random peer(s)
+ */
+#define GNUNET_MESSAGE_TYPE_RPS_CS_REPLY        954
+
+
 /*******************************************************************************/
 
 /**
- * Next available: 904
+ * Next available: 960
  */
 
 /**

+ 83 - 0
src/include/gnunet_rps_service.h

@@ -0,0 +1,83 @@
+/*
+      This file is part of GNUnet
+      (C) 
+
+      GNUnet is free software; you can redistribute it and/or modify
+      it under the terms of the GNU General Public License as published
+      by the Free Software Foundation; either version 3, or (at your
+      option) any later version.
+
+      GNUnet is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with GNUnet; see the file COPYING.  If not, write to the
+      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+      Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file include/gnunet_rps_service.h
+ * @brief API to the rps service
+ * @author Julius Bünger
+ */
+#ifndef GNUNET_RPS_SERVICE_H
+#define GNUNET_RPS_SERVICE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+/**
+ * Version of the rps API.
+ */
+#define GNUNET_RPS_VERSION 0x00000000
+
+typedef void (* GNUNET_RPS_NotifyReadyCB) (void *cls, uint64_t num_peers, struct GNUNET_PeerIdentity *peers);
+
+  struct GNUNET_RPS_Request_Handle *
+GNUNET_RPS_request_peers_single_call (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                          uint64_t n,
+                          GNUNET_RPS_NotifyReadyCB ready_cb,
+                          void *cls);
+
+/**
+ * Connect to the rps service
+ */
+  struct GNUNET_RPS_Handle *
+GNUNET_RPS_connect( const struct GNUNET_CONFIGURATION_Handle *cfg );
+
+/**
+ * Request n random peers.
+ */
+  struct GNUNET_RPS_Request_Handle *
+GNUNET_RPS_request_peers (struct GNUNET_RPS_Handle *h, uint64_t n,
+                          GNUNET_RPS_NotifyReadyCB ready_cb,
+                          void *cls);
+
+/**
+ * Cancle an issued request.
+ */
+  void
+GNUNET_RPS_request_cancel ( struct GNUNET_RPS_Request_Handle *rh );
+
+/**
+ * Disconnect from the rps service
+ */
+  void
+GNUNET_RPS_disconnect ( struct GNUNET_RPS_Handle *h );
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 76 - 0
src/rps/Makefile.am

@@ -0,0 +1,76 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+  AM_CFLAGS = --coverage -O0
+  XLIB = -lgcov
+endif
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfg_DATA = \
+  rps.conf
+
+bin_PROGRAMS = gnunet-rps
+
+gnunet_rps_SOURCES = gnunet-rps.c
+gnunet_rps_LDADD = \
+  libgnunetrps.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(XLIB) $(GN_LIBINTL)
+
+lib_LTLIBRARIES = libgnunetrps.la
+
+libgnunetrps_la_SOURCES = \
+  rps_api.c rps.h
+libgnunetrps_la_LIBADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL) $(XLIB)
+libgnunetrps_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS)  $(WINFLAGS) \
+  -version-info 0:0:0
+
+
+libexec_PROGRAMS = \
+ gnunet-service-rps
+
+
+gnunet_service_rps_SOURCES = \
+ gnunet-service-rps.c
+gnunet_service_rps_LDADD = \
+  libgnunetrps.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
+  $(top_builddir)/src/nse/libgnunetnse.la \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(LIBGCRYPT_LIBS) \
+  -lm -lgcrypt \
+  $(GN_LIBINTL)
+
+if HAVE_TESTING
+check_PROGRAMS = \
+ test_rps_multipeer
+endif
+
+if ENABLE_TEST_RUN
+AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;
+TESTS = $(check_PROGRAMS)
+endif
+
+test_rps_multipeer_SOURCES = \
+ test_rps_multipeer.c
+test_rps_multipeer_LDADD = \
+  libgnunetrps.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(top_builddir)/src/testbed/libgnunettestbed.la \
+  -lm
+
+
+EXTRA_DIST = \
+  test_rps.conf
+

+ 71 - 0
src/rps/gnunet-rps.c

@@ -0,0 +1,71 @@
+/*
+     This file is part of GNUnet.
+     (C)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file rps/gnunet-rps.c
+ * @brief rps tool
+ * @author Julius Bünger
+ */
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "gnunet_rps_service.h"
+
+static int ret;
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  ret = 0;
+}
+
+/**
+ * The main function to rps.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+  return (GNUNET_OK ==
+          GNUNET_PROGRAM_run (argc,
+                              argv,
+                              "gnunet-rps [options [value]]",
+                              gettext_noop
+                              ("rps"),
+                              options, &run, NULL)) ? ret : 1;
+}
+
+/* end of gnunet-rps.c */

+ 1382 - 0
src/rps/gnunet-service-rps.c

@@ -0,0 +1,1382 @@
+/*
+     This file is part of GNUnet.
+     (C)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file rps/gnunet-service-rps.c
+ * @brief rps service implementation
+ * @author Julius Bünger
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_cadet_service.h"
+#include "gnunet_nse_service.h"
+#include "rps.h"
+
+#include <math.h>
+#include <inttypes.h>
+
+#define LOG(kind, ...) GNUNET_log(kind, __VA_ARGS__)
+
+// TODO modify @brief in every file
+
+// TODO take care that messages are not longer than 64k
+
+// TODO check for overflows
+
+// TODO align message structs
+
+// TODO multipeerlist indep of gossiped list
+
+// TODO maybe wait during initialisation some time to get some peers
+//      - initialise peers before proceeding
+//      - Use the magic 0000 peer GNUNET_CADET_get_peers() returns
+
+// (TODO api -- possibility of getting weak random peer immideately)
+
+// TODO malicious peer
+
+// TODO switch Slist -> DLL
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Our own identity.
+ */
+struct GNUNET_PeerIdentity *own_identity;
+
+/**
+ * Compare two peer identities. Taken from secretsharing.
+ *
+ * @param p1 Some peer identity.
+ * @param p2 Some peer identity.
+ * @return 1 if p1 > p2, -1 if p1 < p2 and 0 if p1 == p2.
+ */
+static int
+peer_id_cmp (const void *p1, const void *p2)
+{
+  return memcmp (p1, p2, sizeof (struct GNUNET_PeerIdentity));
+}
+
+/***********************************************************************
+ * Sampler
+ *
+ * WARNING: This section needs to be reviewed regarding the use of
+ * functions providing (pseudo)randomness!
+***********************************************************************/
+
+// TODO init list
+// TODO grow/shrink list
+
+/**
+ * A sampler sampling PeerIDs.
+ */
+struct Sampler
+{
+  /**
+   * Min-wise linear permutation used by this sampler.
+   *
+   * This is an key later used by a hmac.
+   */
+  struct GNUNET_CRYPTO_AuthKey auth_key;
+
+  /**
+   * The PeerID this sampler currently samples.
+   */
+  struct GNUNET_PeerIdentity *peer_id;
+
+  /**
+   * The according hash value of this PeerID.
+   */
+  struct GNUNET_HashCode peer_id_hash;
+
+};
+
+typedef void (* SAMPLER_deleteCB) (void *cls, struct GNUNET_PeerIdentity *id, struct GNUNET_HashCode hash);
+
+/**
+ * (Re)Initialise given Sampler with random min-wise independent function.
+ *
+ * In this implementation this means choosing an auth_key for later use in
+ * a hmac at random.
+ */
+  struct Sampler *
+SAMPLER_init()
+{
+  struct Sampler *s;
+  
+  s = GNUNET_new(struct Sampler);
+
+  // I guess I don't need to call GNUNET_CRYPTO_hmac_derive_key()...
+  GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_STRONG,
+                             &(s->auth_key.key),
+                             GNUNET_CRYPTO_HASH_LENGTH);
+
+  s->peer_id = own_identity; // Maybe set to own PeerID. So we always have
+                     // a valid PeerID in the sampler.
+                     // Maybe take a PeerID as second argument.
+
+  GNUNET_CRYPTO_hmac(&s->auth_key, s->peer_id,
+                     sizeof(struct GNUNET_PeerIdentity),
+                     &s->peer_id_hash);
+
+  return s;
+}
+
+/**
+ * Compare two hashes.
+ *
+ * Returns if the first one is smaller then the second.
+ * Used by SAMPLER_next() to compare hashes.
+ */
+  int
+hash_cmp(struct GNUNET_HashCode hash1, struct GNUNET_HashCode hash2)
+{
+  return memcmp( (const void *) &hash1, (const void *) & hash2, sizeof(struct GNUNET_HashCode)) < 0;
+}
+
+/**
+ * Input an PeerID into the given sampler.
+ */
+  static void
+SAMPLER_next(struct Sampler *s, const struct GNUNET_PeerIdentity *id, SAMPLER_deleteCB del_cb, void *cb_cls)
+{
+  struct GNUNET_HashCode other_hash;
+
+  GNUNET_CRYPTO_hmac(&s->auth_key,
+                     id,
+                     sizeof(struct GNUNET_PeerIdentity),
+                     &other_hash);
+
+  if ( NULL == s->peer_id ) { // Or whatever is a valid way to say
+                              // "we have no PeerID at the moment"
+    *s->peer_id = *id;
+    s->peer_id_hash = other_hash;
+
+  } else {
+
+    if ( hash_cmp(other_hash, s->peer_id_hash) ) {
+      LOG(GNUNET_ERROR_TYPE_DEBUG, "SAMPLER: Got PeerID %s; Discarding old PeerID %s\n",
+          GNUNET_i2s(id), GNUNET_i2s(s->peer_id));
+
+      if ( NULL != del_cb ) {
+        del_cb(cb_cls, s->peer_id, s->peer_id_hash);
+      }
+      *s->peer_id = *id;
+      s->peer_id_hash = other_hash;
+
+    } else {
+      LOG(GNUNET_ERROR_TYPE_DEBUG, "SAMPLER: Got PeerID %s; Keeping old PeerID %s\n",
+          GNUNET_i2s(id), GNUNET_i2s(s->peer_id));
+    }
+
+  }
+}
+
+
+
+/**
+ * A fuction to update every sampler in the given list
+ */
+  static void
+SAMPLER_update_list(struct GNUNET_CONTAINER_SList *lst, const struct GNUNET_PeerIdentity *id,
+                    SAMPLER_deleteCB del_cb, void *cb_cls)
+{
+  struct GNUNET_CONTAINER_SList_Iterator *iter;
+  struct Sampler *sampler;
+  size_t s;
+
+  iter = GNUNET_malloc(sizeof(struct GNUNET_CONTAINER_SList_Iterator));
+  *iter = GNUNET_CONTAINER_slist_begin(lst);
+  s = sizeof(struct Sampler);
+  do {
+    sampler = (struct Sampler *) GNUNET_CONTAINER_slist_get(iter, &s);
+    SAMPLER_next(sampler, id, del_cb, cb_cls);
+  } while ( GNUNET_NO != GNUNET_CONTAINER_slist_next(iter) );
+  
+  GNUNET_CONTAINER_slist_iter_destroy(iter);
+}
+
+/**
+ * Get one random peer out of the sampled peers.
+ *
+ * We might want to reinitialise this sampler after giving the
+ * corrsponding peer to the client.
+ */
+  struct GNUNET_PeerIdentity* 
+SAMPLER_get_rand_peer (struct GNUNET_CONTAINER_SList *lst)
+{
+  uint64_t list_size;
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "SAMPLER_get_rand_peer:\n");
+
+  list_size = (uint64_t) GNUNET_CONTAINER_slist_count(lst);
+
+  if ( 0 == list_size ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Sgrp: List empty - Returning own PeerID %s\n", GNUNET_i2s(own_identity));
+    return own_identity;
+  } else {
+    uint64_t index;
+    struct GNUNET_CONTAINER_SList_Iterator *iter;
+    uint64_t i;
+    size_t s;
+    struct GNUNET_PeerIdentity *peer;
+
+    /**
+     * Choose the index of the peer we want to give back
+     * at random from the interval of the sampler list
+     */
+    index = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG,
+                                     list_size);
+                                     // TODO check that it does not overflow
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Sgrp: Length of Slist: %" PRIu64 ", index: %" PRIu64 "\n", list_size, index);
+
+    s = sizeof( struct Sampler );
+    iter = GNUNET_malloc(sizeof(struct GNUNET_CONTAINER_SList_Iterator));
+    *iter = GNUNET_CONTAINER_slist_begin(lst);
+    for ( i = 0 ; i < index ; i++ ) {
+      if (GNUNET_NO == GNUNET_CONTAINER_slist_next(iter) ) { // Maybe unneeded
+        *iter = GNUNET_CONTAINER_slist_begin(lst);
+      }
+    }
+    
+    // TODO something missing?
+
+    // FIXME this looks wrong:
+    peer = ((struct Sampler *) GNUNET_CONTAINER_slist_get(iter, &s))->peer_id;
+    GNUNET_CONTAINER_slist_iter_destroy(iter);
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Sgrp: Returning PeerID %s (own ID: %s)\n", GNUNET_i2s(peer), GNUNET_i2s(own_identity));
+
+    return peer;
+  }
+}
+
+/**
+ * Get n random peers out of the sampled peers.
+ *
+ * We might want to reinitialise this sampler after giving the
+ * corrsponding peer to the client.
+ * Random with or without consumption?
+ */
+  struct GNUNET_PeerIdentity**  // TODO give back simple array
+SAMPLER_get_n_rand_peers (struct GNUNET_CONTAINER_SList *lst, uint64_t n)
+{
+  // TODO check if we have too much (distinct) sampled peers
+  // If we are not ready yet maybe schedule for later
+  struct GNUNET_PeerIdentity **peers;
+  uint64_t i;
+  
+  peers = GNUNET_malloc(n * sizeof(struct GNUNET_PeerIdentity *));
+
+  for ( i = 0 ; i < n ; i++ ) {
+    peers[i] = SAMPLER_get_rand_peer(lst);
+  }
+
+  // TODO something else missing?
+  return peers;
+}
+
+/**
+ * Counts how many Samplers currently hold a given PeerID.
+ */
+  uint64_t
+SAMPLER_count_id ( struct GNUNET_CONTAINER_SList *lst, struct GNUNET_PeerIdentity *id ) {
+  size_t s;
+  struct GNUNET_CONTAINER_SList_Iterator *iter;
+  uint64_t count;
+
+  s = sizeof( struct Sampler );
+  iter = GNUNET_new(struct GNUNET_CONTAINER_SList_Iterator);
+  *iter = GNUNET_CONTAINER_slist_begin(lst);
+  count = 0;
+  while ( GNUNET_YES == GNUNET_CONTAINER_slist_next(iter) ) {
+    if ( peer_id_cmp( ((struct Sampler *) GNUNET_CONTAINER_slist_get(iter, &s))->peer_id, id) ) {
+      count++;
+    }
+  }
+  GNUNET_CONTAINER_slist_iter_destroy(iter);
+  return count;
+}
+
+
+/***********************************************************************
+ * /Sampler
+***********************************************************************/
+
+
+
+/***********************************************************************
+ * Gossip list
+***********************************************************************/
+
+///**
+// * Get one random peer out of the gossiped peer list.
+// */
+//  struct GNUNET_PeerIdentity *
+//get_random_peer(struct GNUNET_CONTAINER_MultiPeerMap * lst)
+//{
+//  size_t n;
+//  struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
+//  uint64_t index;
+//  uint64_t i;
+//  struct GNUNET_PeerIdentity *peer;
+//
+//  n = (size_t) GNUNET_CONTAINER_multipeermap_size(lst);
+//  index = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG,
+//                                   (uint64_t) n);
+//  iter = GNUNET_CONTAINER_multipeermap_iterator_create(lst);
+//
+//  for ( i = 0 ; i < index ; i++ ) {
+//    GNUNET_CONTAINER_multipeermap_iterator_next(iter, NULL, NULL);
+//  }
+//  
+//  peer = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
+//  GNUNET_CONTAINER_multipeermap_iterator_next(iter, peer, NULL);
+//
+//  return peer;
+//}
+
+
+/***********************************************************************
+ * /Gossip list
+***********************************************************************/
+
+
+
+/***********************************************************************
+ * Housekeeping with peers
+***********************************************************************/
+
+/**
+ * Struct used to store the context of a connected client.
+ */
+struct client_ctx
+{
+  /**
+   * The message queue to communicate with the client.
+   */
+  struct GNUNET_MQ_Handle *mq;
+};
+
+/**
+ * Used to keep track in what lists single peerIDs are.
+ */
+enum in_list_flag // probably unneeded
+{
+  in_other_sampler_list = 0x1,
+  in_other_gossip_list  = 0x2, // unneeded?
+  in_own_sampler_list   = 0x4,
+  in_own_gossip_list    = 0x8 // unneeded?
+};
+
+/**
+ * Struct used to keep track of other peer's status
+ *
+ * This is stored in a multipeermap.
+ */
+struct peer_context
+{
+  /**
+   * In own gossip/sampler list, in other's gossip/sampler list
+   */
+  uint32_t in_flags; // unneeded?
+
+  /**
+   * Message queue open to client
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Channel open to client.
+   */
+  struct GNUNET_CADET_Channel *to_channel;
+
+  /**
+   * Channel open from client.
+   */
+  struct GNUNET_CADET_Channel *from_channel; // unneeded
+
+  /**
+   * This is pobably followed by 'statistical' data (when we first saw
+   * him, how did we get his ID, how many pushes (in a timeinterval),
+   * ...)
+   */
+};
+
+/***********************************************************************
+ * /Housekeeping with peers
+***********************************************************************/
+
+/**
+ * Set of all peers to keep track of them.
+ */
+static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
+
+
+// -- gossip list length --
+// Depends on the (estimated) size of the
+// network. - Initial size might be the
+// number of peers cadet provides.
+// TODO other events to grow/shrink size?
+
+/**
+ * List of samplers
+ */
+struct GNUNET_CONTAINER_SList *sampler_list;
+
+/**
+ * Sampler list size
+ *
+ * Adapts to the nse. Size should be in BigTheta(network_size)^(1/3).
+ */
+size_t sampler_list_size;
+
+
+/**
+ * The gossiped list of peers.
+ */
+struct GNUNET_PeerIdentity *gossip_list;
+
+/**
+ * Size of the gossiped list
+ */
+unsigned int gossip_list_size;
+
+/**
+ * Min size of the gossip list
+ */
+uint64_t gossip_list_min_size;
+
+///**
+// * Max size of the gossip list
+// * 
+// * This will probably be left to be set by the client.
+// */
+//uint64_t gossip_list_max_size;
+
+
+/**
+ * The estimated size of the network.
+ *
+ * Influenced by the stdev.
+ */
+size_t est_size;
+
+
+
+/**
+ * Percentage of total peer number in the gossip list
+ * to send random PUSHes to
+ */
+float alpha;
+
+/**
+ * Percentage of total peer number in the gossip list
+ * to send random PULLs to
+ */
+float beta;
+
+/**
+ * The percentage gamma of history updates.
+ * Simply 1 - alpha - beta
+ */
+
+
+
+
+/**
+ * Identifier for the main task that runs periodically.
+ */
+GNUNET_SCHEDULER_TaskIdentifier do_round_task;
+
+/**
+ * Time inverval the do_round task runs in.
+ */
+struct GNUNET_TIME_Relative round_interval;
+
+
+
+/**
+ * List to store peers received through pushes temporary.
+ */
+struct GNUNET_CONTAINER_SList *push_list;
+
+/**
+ * List to store peers received through pulls temporary.
+ */
+struct GNUNET_CONTAINER_SList *pull_list;
+
+
+/**
+ * Handler to NSE.
+ */
+struct GNUNET_NSE_Handle *nse;
+
+/**
+ * Handler to CADET.
+ */
+struct GNUNET_CADET_Handle *cadet_handle;
+
+
+/***********************************************************************
+ * Util functions
+***********************************************************************/
+
+/**
+ * Get random peer from the gossip list.
+ */
+  struct GNUNET_PeerIdentity *
+get_rand_gossip_peer()
+{
+  uint64_t index;
+  struct GNUNET_PeerIdentity *peer;
+
+  // TODO find a better solution.
+  // FIXME if we have only own ID in gossip list this will block
+  // but then we might have a problem nevertheless ?
+
+  do {
+
+    /**;
+     * Choose the index of the peer we want to return
+     * at random from the interval of the gossip list
+     */
+    index = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG,
+                                     gossip_list_size);
+
+    peer = &(gossip_list[index]);
+  } while ( own_identity == peer || NULL == peer );
+
+  return peer;
+}
+
+/**
+ * Get the message queue of a specific peer.
+ *
+ * If we already have a message queue open to this client,
+ * simply return it, otherways create one.
+ */
+  struct GNUNET_MQ_Handle *
+get_mq (struct GNUNET_CONTAINER_MultiPeerMap *peer_map, struct GNUNET_PeerIdentity *peer_id)
+{
+  struct peer_context *ctx;
+  struct GNUNET_MQ_Handle * mq;
+  struct GNUNET_CADET_Channel *channel;
+
+  if ( GNUNET_OK != GNUNET_CONTAINER_multipeermap_contains( peer_map, peer_id ) ) {
+
+    channel = GNUNET_CADET_channel_create(cadet_handle, NULL, peer_id,
+                                  GNUNET_RPS_CADET_PORT,
+                                  GNUNET_CADET_OPTION_RELIABLE);
+    mq = GNUNET_CADET_mq_create(channel);
+
+    ctx = GNUNET_malloc(sizeof(struct peer_context));
+    ctx->in_flags = 0;
+    ctx->to_channel = channel;
+    ctx->mq = mq;
+
+    GNUNET_CONTAINER_multipeermap_put(peer_map, peer_id, ctx,
+                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+  } else {
+    ctx = GNUNET_CONTAINER_multipeermap_get(peer_map, peer_id);
+    if ( NULL == ctx->mq ) {
+      if ( NULL == ctx->to_channel ) {
+        channel = GNUNET_CADET_channel_create(cadet_handle, NULL, peer_id,
+                                      GNUNET_RPS_CADET_PORT,
+                                      GNUNET_CADET_OPTION_RELIABLE);
+        ctx->to_channel = channel;
+      }
+
+      mq = GNUNET_CADET_mq_create(ctx->to_channel);
+      ctx->mq = mq;
+    }
+  }
+
+  return ctx->mq;
+}
+
+
+/***********************************************************************
+ * /Util functions
+***********************************************************************/
+
+/**
+ * Function called by NSE.
+ *
+ * Updates sizes of sampler list and gossip list and adapt those lists
+ * accordingly.
+ */
+  void
+nse_callback(void *cls, struct GNUNET_TIME_Absolute timestamp, double logestimate, double std_dev)
+{
+  double estimate;
+  //double scale; // TODO this might go gloabal/config
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Received a ns estimate - logest: %f, std_dev: %f\n", logestimate, std_dev);
+  //scale = .01;
+  estimate = 1 << (uint64_t) round(logestimate);
+  // GNUNET_NSE_log_estimate_to_n (logestimate);
+  estimate = pow(estimate, 1./3);// * (std_dev * scale); // TODO add
+  if ( 0 < estimate ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Changing estimate to %f\n", estimate);
+    est_size = estimate;
+  } else {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Not using estimate %f\n", estimate);
+  }
+}
+
+/**
+ * Handle RPS request from the client.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+// TODO rename
+handle_cs_request (void *cls,
+            struct GNUNET_SERVER_Client *client,
+            const struct GNUNET_MessageHeader *message)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Client requested (a) random peer(s).\n");
+
+  struct GNUNET_RPS_CS_RequestMessage *msg;
+  //unsigned int n_arr[sampler_list_size];// =
+    //GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_STRONG, (unsigned int) sampler_list_size);
+  //struct GNUNET_MQ_Handle *mq;
+  struct client_ctx *cli_ctx;
+  struct GNUNET_MQ_Envelope *ev;
+  struct GNUNET_RPS_CS_ReplyMessage *out_msg;
+  uint64_t num_peers;
+  uint64_t i;
+
+  // TODO
+  msg = (struct GNUNET_RPS_CS_RequestMessage *) message;
+  // Does not work because the compiler seems not to find it.
+  cli_ctx = GNUNET_SERVER_client_get_user_context(client, struct client_ctx);
+  if ( NULL == cli_ctx ) {
+    cli_ctx = GNUNET_new(struct client_ctx);
+    cli_ctx->mq = GNUNET_MQ_queue_for_server_client(client);
+    GNUNET_SERVER_client_set_user_context(client, cli_ctx);
+  }
+  
+  //mq = GNUNET_MQ_queue_for_server_client(client);
+    
+  // TODO How many peers do we give back?
+  // Wait until we have enough random peers?
+
+  ev = GNUNET_MQ_msg_extra(out_msg,
+                           GNUNET_ntohll(msg->num_peers) * sizeof(struct GNUNET_PeerIdentity),
+                           GNUNET_MESSAGE_TYPE_RPS_CS_REPLY);
+  out_msg->num_peers = GNUNET_ntohll(msg->num_peers);
+
+  num_peers = GNUNET_ntohll(msg->num_peers);
+  //&out_msg[1] = SAMPLER_get_n_rand_peers(sampler_list, num_peers);
+  for ( i = 0 ; i < num_peers ; i++ ) {
+    memcpy(&out_msg[1] + i * sizeof(struct GNUNET_PeerIdentity),
+           SAMPLER_get_rand_peer(sampler_list),
+           sizeof(struct GNUNET_PeerIdentity));
+  }
+  
+  GNUNET_MQ_send(cli_ctx->mq, ev);
+  //GNUNET_MQ_send(mq, ev);
+  //GNUNET_MQ_destroy(mq);
+
+  GNUNET_SERVER_receive_done (client,
+			      GNUNET_OK);
+}
+
+/**
+ * Handle a PUSH message from another peer.
+ *
+ * Check the proof of work and store the PeerID
+ * in the temporary list for pushed PeerIDs.
+ *
+ * @param cls Closure
+ * @param channel The channel the PUSH was received over
+ * @param channel_ctx The context associated with this channel
+ * @param msg The message header
+ */
+static int
+handle_peer_push (void *cls,
+    struct GNUNET_CADET_Channel *channel,
+    void **channel_ctx,
+    const struct GNUNET_MessageHeader *msg)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "PUSH received\n");
+
+  struct GNUNET_PeerIdentity *peer;
+
+  // TODO check the proof of work
+  // and check limit for PUSHes
+  // IF we count per peer PUSHes
+  // maybe remove from gossip/sampler list
+  
+  peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info( channel, GNUNET_CADET_OPTION_PEER );
+  
+  /* Add the sending peer to the push_list */
+  GNUNET_CONTAINER_slist_add(push_list,
+                             GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                             peer, sizeof(struct GNUNET_PeerIdentity));
+
+  return GNUNET_OK;
+}
+
+/**
+ * Handle PULL REQUEST request message from another peer.
+ *
+ * Reply with the gossip list of PeerIDs.
+ *
+ * @param cls Closure
+ * @param channel The channel the PUSH was received over
+ * @param channel_ctx The context associated with this channel
+ * @param msg The message header
+ */
+static int
+handle_peer_pull_request (void *cls,
+    struct GNUNET_CADET_Channel *channel,
+    void **channel_ctx,
+    const struct GNUNET_MessageHeader *msg)
+{
+
+  struct GNUNET_PeerIdentity *peer;
+  struct GNUNET_MQ_Handle *mq;
+  //struct GNUNET_RPS_P2P_PullRequestMessage *in_msg;
+  struct GNUNET_MQ_Envelope *ev;
+  struct GNUNET_RPS_P2P_PullReplyMessage *out_msg;
+
+  // TODO find some way to keep one peer from spamming with pull requests
+  // allow only one request per time interval ?
+  // otherwise remove from peerlist?
+
+  peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info(channel, GNUNET_CADET_OPTION_PEER);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "PULL REQUEST from peer %s received\n", GNUNET_i2s(peer));
+
+  mq = GNUNET_CADET_mq_create(channel); // TODO without mq?
+  //mq = get_mq(peer_map, peer);
+
+  //in_msg = (struct GNUNET_RPS_P2P_PullRequestMessage *) msg;
+  // TODO how many peers do we actually send?
+  // GNUNET_ntohll(in_msg->num_peers)
+  ev = GNUNET_MQ_msg_extra(out_msg,
+                           gossip_list_size * sizeof(struct GNUNET_PeerIdentity),
+                           GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY);
+  out_msg->num_peers = GNUNET_htonll(gossip_list_size);
+  memcpy(&out_msg[1], gossip_list,
+         gossip_list_size * sizeof(struct GNUNET_PeerIdentity));
+
+  GNUNET_MQ_send(mq, ev);
+
+  GNUNET_MQ_destroy(mq);
+
+
+  return GNUNET_OK;
+}
+
+/**
+ * Handle PULL REPLY message from another peer.
+ *
+ * Check whether we sent a corresponding request and
+ * whether this reply is the first one.
+ *
+ * @param cls Closure
+ * @param channel The channel the PUSH was received over
+ * @param channel_ctx The context associated with this channel
+ * @param msg The message header
+ */
+static int
+handle_peer_pull_reply (void *cls,
+    struct GNUNET_CADET_Channel *channel,
+    void **channel_ctx,
+    const struct GNUNET_MessageHeader *msg)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "PULL REPLY received\n");
+
+  struct GNUNET_RPS_P2P_PullReplyMessage *in_msg;
+  uint64_t i;
+
+  // TODO check that we sent a request and that it is the first reply
+
+  in_msg = (struct GNUNET_RPS_P2P_PullReplyMessage *) msg;
+  for ( i = 0 ; i < in_msg->num_peers ; i++ ) {
+    GNUNET_CONTAINER_slist_add(pull_list,
+                               GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                               &in_msg[1] + i * sizeof(struct GNUNET_PeerIdentity),
+                               sizeof(struct GNUNET_PeerIdentity));
+  }
+
+  // TODO maybe a disconnect happens here
+  
+  return GNUNET_OK;
+}
+
+
+/**
+ * Callback called when a Sampler is updated.
+ */
+  void
+delete_cb (void *cls, struct GNUNET_PeerIdentity *id, struct GNUNET_HashCode hash)
+{
+  size_t s;
+
+  s = SAMPLER_count_id(sampler_list, id);
+  if ( 1 >= s ) {
+    // TODO cleanup peer
+    GNUNET_CONTAINER_multipeermap_remove_all( peer_map, id);
+  }
+}
+
+
+/**
+ * Send out PUSHes and PULLs.
+ *
+ * This is executed regylary.
+ */
+static void
+do_round(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Going to execute next round\n");
+
+  uint64_t i;
+  struct Sampler *s;
+  struct GNUNET_CONTAINER_SList_Iterator *iter;
+  //unsigned int *n_arr;
+  struct GNUNET_RPS_P2P_PushMessage        *push_msg;
+  struct GNUNET_RPS_P2P_PullRequestMessage *pull_msg; // FIXME Send empty message
+  struct GNUNET_MQ_Envelope *ev;
+  struct GNUNET_PeerIdentity *peer;
+
+  // TODO print lists, ...
+  // TODO cleanup peer_map
+
+  iter = GNUNET_new(struct GNUNET_CONTAINER_SList_Iterator);
+
+
+  /* If the NSE has changed adapt the lists accordingly */
+  // TODO check nse == 0!
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Checking size estimate.\n");
+  if ( sampler_list_size < est_size ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Growing size.\n");
+    /* Grow the lists. */
+    for ( i = 0 ; i < est_size - sampler_list_size ; i++ ) {
+      s = SAMPLER_init();
+      GNUNET_CONTAINER_slist_add_end(sampler_list,
+                                     GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, // DEPRECATED
+                                     s,
+                                     sizeof(struct Sampler));
+
+      // TODO add peers to gossiped ones?
+    }
+  } else if ( sampler_list_size > est_size ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Shrinking size.\n");
+    /* Shrink the lists. */
+    for ( i = 0 ; i < sampler_list_size - est_size ; i++ ) {
+      *iter = GNUNET_CONTAINER_slist_begin(sampler_list);
+      GNUNET_CONTAINER_slist_erase(iter);
+      GNUNET_CONTAINER_slist_iter_destroy(iter); // Maybe unneeded but I don't know whether _erase() also deletes the iter
+    }
+  }
+
+  GNUNET_array_grow(gossip_list, gossip_list_size, est_size); // FIXME Do conversion correct or change type
+
+  gossip_list_size = sampler_list_size = est_size;
+
+ 
+
+
+  /* Would it make sense to have one shuffeled gossip list and then
+   * to send PUSHes to first alpha peers, PULL requests to next beta peers and
+   * use the rest to update sampler? */
+
+  /* Send PUSHes */
+  //n_arr = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_STRONG, (unsigned int) gossip_list_size);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Going to send pushes to %f (%f * %" PRIu64 ") peers.\n",
+      alpha * gossip_list_size, alpha, gossip_list_size);
+  for ( i = 0 ; i < alpha * gossip_list_size ; i++ ) { // TODO compute length
+    peer = get_rand_gossip_peer();
+    // TODO check NULL == peer
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Sending PUSH to peer %s of gossiped list.\n", GNUNET_i2s(peer));
+
+    ev = GNUNET_MQ_msg(push_msg, GNUNET_MESSAGE_TYPE_RPS_PP_PUSH);
+    //ev = GNUNET_MQ_msg_extra();
+    /* TODO Compute proof of work here
+    push_msg; */
+    push_msg->placeholder = 0;
+    GNUNET_MQ_send( get_mq(peer_map, peer), ev );
+
+    // TODO modify in_flags of respective peer?
+  }
+
+
+  /* Send PULL requests */
+  // TODO
+  //n_arr = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_STRONG, (unsigned int) sampler_list_size);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Going to send pulls to %f (%f * %" PRIu64 ") peers.\n",
+      beta * gossip_list_size, beta, gossip_list_size);
+  for ( i = 0 ; i < beta * gossip_list_size ; i++ ){ // TODO compute length
+    peer = get_rand_gossip_peer();
+    // TODO check NULL == peer
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Sending PULL request to peer %s of gossiped list.\n", GNUNET_i2s(peer));
+
+    ev = GNUNET_MQ_msg(pull_msg, GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST);
+    //ev = GNUNET_MQ_msg_extra();
+    pull_msg->placeholder = 0;
+    GNUNET_MQ_send( get_mq(peer_map, peer), ev );
+    // TODO modify in_flags of respective peer?
+  }
+
+
+
+
+  /* Update gossip list */
+  uint64_t tmp_index;
+
+  if ( GNUNET_CONTAINER_slist_count(push_list) <= alpha * gossip_list_size &&
+       GNUNET_CONTAINER_slist_count(push_list) != 0 &&
+       GNUNET_CONTAINER_slist_count(pull_list) != 0 ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Update of the gossip list. ()\n");
+
+    for ( i = 0 ; i < alpha * gossip_list_size ; i++ ) { // TODO use SAMPLER_get_n_rand_peers
+      /* Update gossip list with peers received through PUSHes */
+      gossip_list[i] = *SAMPLER_get_rand_peer(push_list);
+      // TODO change the in_flags accordingly
+    }
+
+    for ( i = 0 ; i < beta * gossip_list_size ; i++ ) {
+      /* Update gossip list with peers received through PULLs */
+      tmp_index = i + round(alpha * gossip_list_size);
+      gossip_list[tmp_index] = *SAMPLER_get_rand_peer(pull_list);
+      // TODO change the in_flags accordingly
+    }
+
+    for ( i = 0 ; i < (1 - (alpha + beta)) * gossip_list_size ; i++ ) {
+      /* Update gossip list with peers from history */
+      tmp_index = i + round((alpha + beta) * gossip_list_size);
+      gossip_list[tmp_index] = *SAMPLER_get_rand_peer(sampler_list);
+      // TODO change the in_flags accordingly
+    }
+
+  } else {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "No update of the gossip list. ()\n");
+  }
+  // TODO independent of that also get some peers from CADET_get_peers()?
+
+
+
+  /* Update samplers */
+  size_t size;
+
+  if ( 0 < GNUNET_CONTAINER_slist_count(push_list) ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Update of the sampler list from pushes.\n");
+
+    *iter = GNUNET_CONTAINER_slist_begin(push_list);
+    size = sizeof(struct GNUNET_PeerIdentity);
+
+    while ( GNUNET_NO != GNUNET_CONTAINER_slist_next(iter) ) {
+      peer = (struct GNUNET_PeerIdentity *) GNUNET_CONTAINER_slist_get(iter, &size);
+      SAMPLER_update_list(sampler_list, peer, NULL, NULL);
+      // TODO set in_flag
+    }
+    GNUNET_CONTAINER_slist_iter_destroy(iter);
+
+  } else {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "No update of the sampler list - received no pushes.\n");
+  }
+
+  if ( 0 < GNUNET_CONTAINER_slist_count(pull_list) ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Update of the sampler list - received no pushes.\n");
+
+    *iter = GNUNET_CONTAINER_slist_begin(pull_list);
+
+    while ( GNUNET_NO != GNUNET_CONTAINER_slist_next(iter) ) {
+      peer = (struct GNUNET_PeerIdentity *) GNUNET_CONTAINER_slist_get(iter, &size);
+      SAMPLER_update_list(sampler_list, peer, NULL, NULL);
+      // TODO set in_flag
+    }
+    GNUNET_CONTAINER_slist_iter_destroy(iter);
+  } else {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "No update of the sampler list - received no pulls.\n");
+  }
+
+
+  GNUNET_free(iter);
+
+
+  // TODO go over whole peer_map and do cleanups
+  // delete unneeded peers, set in_flags, check channel/mq
+
+
+
+  /* Empty push/pull lists */
+  if ( 0 != GNUNET_CONTAINER_slist_count(push_list) ) {
+      GNUNET_CONTAINER_slist_clear(push_list);
+  }
+
+  if ( 0 != GNUNET_CONTAINER_slist_count(push_list) ) {
+    GNUNET_CONTAINER_slist_clear(push_list);
+  }
+
+
+  /* Schedule next round */
+  // TODO
+  do_round_task = GNUNET_SCHEDULER_add_delayed( round_interval, &do_round, NULL );
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Finished round\n");
+}
+
+static void
+rps_start (struct GNUNET_SERVER_Handle *server);
+
+/**
+ * This is called from GNUNET_CADET_get_peers().
+ *
+ * It is called on every peer(ID) that cadet somehow has contact with.
+ * We use those to initialise the sampler.
+ */
+void
+init_peer_cb (void *cls,
+              const struct GNUNET_PeerIdentity *peer,
+              int tunnel, // "Do we have a tunnel towards this peer?"
+              unsigned int n_paths, // "Number of known paths towards this peer"
+              unsigned int best_path) // "How long is the best path?
+                                      // (0 = unknown, 1 = ourselves, 2 = neighbor)"
+{
+  // FIXME use the magic 0000 PeerID
+  if ( NULL != peer ) {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Got peer %s from CADET\n", GNUNET_i2s(peer));
+    SAMPLER_update_list(sampler_list, peer, NULL, NULL);
+    if ( GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains( peer_map, peer ) ) {
+    } else {
+      struct peer_context *ctx;
+
+      ctx = GNUNET_malloc(sizeof(struct peer_context));
+      ctx->in_flags = 0;
+      ctx->mq = NULL;
+      ctx->to_channel = NULL;
+      ctx->from_channel = NULL;
+      GNUNET_CONTAINER_multipeermap_put( peer_map, peer, ctx, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+    }
+
+    uint64_t i;
+    i = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG, gossip_list_size);
+    gossip_list[i] = *peer;
+    // TODO send push/pull to each of those peers?
+  } else {
+    rps_start( (struct GNUNET_SERVER_Handle *) cls);
+  }
+}
+
+
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls,
+	       const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "RPS is going down\n");
+
+  GNUNET_NSE_disconnect(nse);
+  GNUNET_CADET_disconnect(cadet_handle);
+  // TODO delete global data
+}
+
+
+/**
+ * A client disconnected.  Remove all of its data structure entries.
+ *
+ * @param cls closure, NULL
+ * @param client identification of the client
+ */
+static void
+handle_client_disconnect (void *cls,
+			  struct GNUNET_SERVER_Client * client)
+{
+  // TODO reinitialise that sampler
+}
+
+/**
+ * Handle the channel a peer opens to us.
+ *
+ * @param cls The closure
+ * @param channel The channel the peer wants to establish
+ * @param initiator The peer's peer ID
+ * @param port The port the channel is being established over
+ * @param options Further options
+ */
+  static void *
+handle_inbound_channel (void *cls,
+                        struct GNUNET_CADET_Channel *channel,
+                        const struct GNUNET_PeerIdentity *initiator,
+                        uint32_t port,
+                        enum GNUNET_CADET_ChannelOption options)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "New channel was established to us.\n");
+
+  GNUNET_assert( NULL != channel );
+
+  // TODO we might even not store the from_channel
+
+  if ( GNUNET_CONTAINER_multipeermap_contains( peer_map, initiator ) ) {
+    ((struct peer_context *) GNUNET_CONTAINER_multipeermap_get( peer_map, initiator ))->from_channel = channel;
+    // FIXME there might already be an established channel
+  } else {
+    struct peer_context *ctx;
+
+    ctx = GNUNET_malloc( sizeof(struct peer_context));
+    ctx->in_flags = in_other_gossip_list;
+    ctx->mq = NULL; // TODO create mq?
+    ctx->from_channel = channel;
+
+    GNUNET_CONTAINER_multipeermap_put( peer_map, initiator, ctx, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+  }
+  return NULL; // TODO
+}
+
+/**
+ * This is called when a remote peer destroys a channel.
+ *
+ * @param cls The closure
+ * @param channel The channel being closed
+ * @param channel_ctx The context associated with this channel
+ */
+static void
+cleanup_channel(void *cls,
+                const struct GNUNET_CADET_Channel *channel,
+                void *channel_ctx)
+{
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Channel was destroyed by remote peer.\n");
+}
+
+/**
+ * Actually start the service.
+ */
+static void
+rps_start (struct GNUNET_SERVER_Handle *server)
+{
+  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+    {&handle_cs_request, NULL, GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST, 0},
+    {NULL, NULL, 0, 0}
+  };
+
+  GNUNET_SERVER_add_handlers (server, handlers);
+  GNUNET_SERVER_disconnect_notify (server,
+				   &handle_client_disconnect,
+				   NULL);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Ready to receive requests from clients\n");
+
+
+
+  do_round_task = GNUNET_SCHEDULER_add_delayed( round_interval, &do_round, NULL);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Scheduled first round\n");
+
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+				&shutdown_task,
+				NULL);
+}
+
+
+
+/**
+ * Process statistics requests.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+     struct GNUNET_SERVER_Handle *server,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  // TODO check what this does -- copied from gnunet-boss
+  // - seems to work as expected
+  GNUNET_log_setup("rps", GNUNET_error_type_to_string(GNUNET_ERROR_TYPE_DEBUG), NULL);
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "RPS started\n");
+
+  uint32_t i;
+
+  cfg = c;
+
+
+  own_identity = GNUNET_new(struct GNUNET_PeerIdentity);
+
+  GNUNET_CRYPTO_get_peer_identity(cfg, own_identity);
+
+
+
+  /* Get time interval from the configuration */
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "RPS",
+                                                        "ROUNDINTERVAL",
+                                                        &round_interval))
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Failed to read ROUNDINTERVAL from config\n");
+    GNUNET_SCHEDULER_shutdown();
+    return;
+  }
+
+  /* Get initial size of sampler/gossip list from the configuration */
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "RPS",
+                                                         "INITSIZE",
+                                                         (long long unsigned int *) &est_size)) // FIXME convert
+  {
+    LOG(GNUNET_ERROR_TYPE_DEBUG, "Failed to read INITSIZE from config\n");
+    GNUNET_SCHEDULER_shutdown();
+    return;
+  }
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "INITSIZE is %" PRIu64 "\n", est_size);
+
+  gossip_list_size = sampler_list_size = est_size; // TODO rename est_size
+
+
+  gossip_list = NULL;
+
+  static unsigned int tmp = 0;
+
+  GNUNET_array_grow(gossip_list, tmp, gossip_list_size);
+
+
+
+  /* connect to NSE */
+  nse = GNUNET_NSE_connect(cfg, nse_callback, NULL);
+  // TODO check whether that was successful
+  // TODO disconnect on shutdown
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Connected to NSE\n");
+
+
+  alpha = 0.45;
+  beta  = 0.45;
+  // TODO initialise thresholds - ?
+
+  ///* Get alpha from the configuration */
+  //if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_float (cfg, "RPS",
+  //                                                       "ALPHA",
+  //                                                       &alpha))
+  //{
+  //  LOG(GNUNET_ERROR_TYPE_DEBUG, "No ALPHA specified in the config\n");
+  //}
+  //LOG(GNUNET_ERROR_TYPE_DEBUG, "ALPHA is %f\n", alpha);
+ 
+  ///* Get beta from the configuration */
+  //if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_float (cfg, "RPS",
+  //                                                       "BETA",
+  //                                                       &beta))
+  //{
+  //  LOG(GNUNET_ERROR_TYPE_DEBUG, "No BETA specified in the config\n");
+  //}
+  //LOG(GNUNET_ERROR_TYPE_DEBUG, "BETA is %f\n", beta);
+
+
+
+
+  peer_map = GNUNET_CONTAINER_multipeermap_create(est_size, GNUNET_NO);
+
+
+  /* Initialise sampler and gossip list */
+  struct Sampler *s;
+
+  sampler_list = GNUNET_CONTAINER_slist_create();
+
+  //if ( gossip_list_size == sampler_list_size ) {
+    for ( i = 0 ; i < sampler_list_size ; i++ ) {
+      /* Init sampler list */
+      s = SAMPLER_init();
+      GNUNET_CONTAINER_slist_add(sampler_list,
+                                 GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC, // TODO DEPRECATED
+                                 s,
+                                 sizeof(struct Sampler));
+      /* Init gossip list */
+        // TODO init gossip list
+        // What do we need to do here?
+    }
+  //} else {
+  //  for ( i = 0 ; i < gossip_list_size ; i++ ) {
+  //    // TODO init gossip list
+  //  }
+  //  for ( i = 0 ; i < sampler_list_size ; i++ ) {
+  //    // TODO init RPF func
+  //    // TODO init Sample list
+  //    // TODO init Sampled list
+  //  }
+  //}
+  uint64_t tmp_s = (uint64_t) GNUNET_CONTAINER_slist_count(sampler_list);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Initialised sampler list %" PRIu64 "\n", tmp_s);
+
+
+
+  push_list = GNUNET_CONTAINER_slist_create();
+  pull_list = GNUNET_CONTAINER_slist_create();
+
+
+
+  static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
+    {&handle_peer_push        , GNUNET_MESSAGE_TYPE_RPS_PP_PUSH        , 0},
+    {&handle_peer_pull_request, GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST, 0},
+    {&handle_peer_pull_reply  , GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY  , 0},
+    {NULL, 0, 0}
+  };
+
+  const uint32_t ports[] = {GNUNET_RPS_CADET_PORT, 0}; // _PORT specified in src/rps/rps.h
+  cadet_handle = GNUNET_CADET_connect(cfg,
+                                    cls,
+                                    &handle_inbound_channel,
+                                    &cleanup_channel,
+                                    cadet_handlers,
+                                    ports);
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Connected to CADET\n");
+
+
+  LOG(GNUNET_ERROR_TYPE_DEBUG, "Requesting peers from CADET\n");
+  GNUNET_CADET_get_peers(cadet_handle, &init_peer_cb, server);
+  // FIXME use magic 0000 PeerID to _start_ the service
+
+  // TODO send push/pull to each of those peers?
+
+
+
+}
+
+
+/**
+ * The main function for the rps service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  return (GNUNET_OK ==
+          GNUNET_SERVICE_run (argc,
+                              argv,
+                              "rps",
+			      GNUNET_SERVICE_OPTION_NONE,
+			      &run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-rps.c */

+ 7 - 0
src/rps/rps.conf.in

@@ -0,0 +1,7 @@
+[rps]
+BINARY = gnunet-service-rps
+UNIXPATH = /tmp/gnunet-service-rps.sock
+HOME = $SERVICEHOME
+# PORT = 2106
+@UNIXONLY@ PORT = 2087
+

+ 139 - 0
src/rps/rps.h

@@ -0,0 +1,139 @@
+/*
+      This file is part of GNUnet
+      (C) 2012-2013 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
+      by the Free Software Foundation; either version 3, or (at your
+      option) any later version.
+
+      GNUnet is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with GNUnet; see the file COPYING.  If not, write to the
+      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+      Boston, MA 02111-1307, USA.
+ */
+/**
+ * @file rps/rps.h
+ * @brief example IPC messages between RPS API and GNS service
+ * @author Julius Bünger
+ */
+
+#include "gnunet_rps_service.h"
+
+/**
+ * Mesh port used by RPS.
+ */
+#define GNUNET_RPS_CADET_PORT 31337
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/***********************************************************************
+ * P2P Messages
+***********************************************************************/
+
+/**
+ * P2P Message to push own ID to other peer.
+ */
+struct GNUNET_RPS_P2P_PushMessage
+{
+  /**
+   * Header including size and type in NBO
+   */
+  struct GNUNET_MessageHeader header;
+
+  /** 
+   * TODO Proof of work
+   */
+  uint64_t placeholder;
+};
+
+/**
+ * P2P Message to request PeerIDs from other peer.
+ */
+struct GNUNET_RPS_P2P_PullRequestMessage
+{
+  /**
+   * Header including size and type in NBO
+   */
+  struct GNUNET_MessageHeader header;
+
+  /* This probably stays empty as we just
+   * infrom the peer of our existence */
+  uint64_t placeholder;
+};
+
+/**
+ * P2P Message to send PeerIDs to other peer.
+ */
+struct GNUNET_RPS_P2P_PullReplyMessage
+{
+  /**
+   * Header including size and type in NBO
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Number of PeerIDs sent
+   */
+  uint64_t num_peers GNUNET_PACKED;
+
+  /* Followed by num_peers * GNUNET_PeerIdentity */
+};
+
+
+
+/***********************************************************************
+ * Client-Service Messages
+***********************************************************************/
+
+/**
+ * Message from client to RPS service to request random peer(s).
+ */
+struct GNUNET_RPS_CS_RequestMessage
+{
+  /**
+   * Header including size and type in NBO
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Identifyer of the message.
+   */
+  uint64_t n;
+
+  /**
+   * Number of random peer requested
+   */
+  uint64_t num_peers GNUNET_PACKED;
+};
+
+/**
+ * Message from RPS service to client to reply with random peer(s).
+ */
+struct GNUNET_RPS_CS_ReplyMessage
+{
+  /**
+   * Header including size and type in NBO
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Identifyer of the message.
+   */
+  uint64_t n;
+
+  /**
+   * Number of random peer replied
+   */
+  uint64_t num_peers GNUNET_PACKED;
+
+  /* Followed by num_peers * GNUNET_PeerIdentity */
+};
+
+GNUNET_NETWORK_STRUCT_END

+ 279 - 0
src/rps/rps_api.c

@@ -0,0 +1,279 @@
+/*
+     This file is part of GNUnet.
+     (C) 
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file rps/rps_api.c
+ * @brief API for rps
+ * @author Julius Bünger
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "rps.h"
+#include "gnunet_rps_service.h"
+
+/**
+ * Handler to handle requests from a client.
+ */
+struct GNUNET_RPS_Handle
+{
+  /**
+   * The handle to the client configuration.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * The connection to the client.
+   */
+  struct GNUNET_CLIENT_Connection *conn;
+
+  /**
+   * The message queue to the client.
+   */
+  struct GNUNET_MQ_Handle *mq;
+};
+
+/**
+ * Handler to single requests from the client.
+ */
+struct GNUNET_RPS_Request_Handle
+{
+  /**
+   * The client issuing the request.
+   */
+  struct GNUNET_RPS_Handle *h;
+
+  /**
+   * The nuber of the request.
+   */
+  uint64_t n;
+
+  /**
+   * The callback to be called when we receive an answer.
+   */
+  GNUNET_RPS_NotifyReadyCB ready_cb;
+
+  /**
+   * The closure for the callback.
+   */
+  void *ready_cb_cls;
+};
+
+/**
+ * Array of Request_Handles.
+ */
+struct GNUNET_RPS_Request_Handle *req_handlers = NULL;
+
+/**
+ * Current length of req_handlers.
+ */
+unsigned int req_handlers_size = 0;
+
+/**
+ * Struct used to pack the callback, its closure (provided by the caller)
+ * and the connection handler to the service to pass it to a callback function.
+ */
+struct cb_cls_pack
+{
+  /**
+   * Callback provided by the client
+   */
+  GNUNET_RPS_NotifyReadyCB cb;
+
+  /**
+   * Closure provided by the client
+   */
+  void *cls;
+
+  /**
+   * Handle to the service connection
+   */
+ struct GNUNET_CLIENT_Connection *service_conn;
+};
+
+
+
+
+/**
+ * This function is called, when the service replies to our request.
+ * It calls the callback the caller gave us with the provided closure
+ * and disconnects afterwards.
+ *
+ * @param cls the closure
+ * @param message the message
+ */
+  static void
+handle_reply (void *cls,
+              const struct GNUNET_MessageHeader *message)
+{
+  struct GNUNET_RPS_CS_ReplyMessage *msg;
+  //struct cb_cls_pack *pack;
+  //struct GNUNET_RPS_Handle *h;
+  struct GNUNET_PeerIdentity *peers;
+  struct GNUNET_RPS_Request_Handle *rh;
+
+  /* Give the peers back */
+  msg = (struct GNUNET_RPS_CS_ReplyMessage *) message;
+  //pack = (struct cb_cls_pack *) cls;
+  //h = (struct GNUNET_RPS_Handle *) cls;
+  peers = (struct GNUNET_PeerIdentity *) &msg[1];
+  rh = &req_handlers[msg->n];
+  rh->ready_cb((rh)->ready_cb_cls, msg->num_peers, peers);
+
+  /* Disconnect */
+  //GNUNET_CLIENT_disconnect(pack->service_conn);
+}
+
+/**
+ */
+  static void
+mq_error_handler(void *cls, enum GNUNET_MQ_Error error)
+{
+  //TODO LOG
+}
+
+/**
+ * Request n random peers.
+ *
+ * @param cfg the configuration to use.
+ * @param n number of peers requesting.
+ * @param cb a callback function called when the peers are ready
+ * @param cls a closure given to the callback function
+ */
+  struct GNUNET_RPS_Request_Handle *
+GNUNET_RPS_request_peers_single_call (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                          uint64_t n,
+                          GNUNET_RPS_NotifyReadyCB ready_cb,
+                          void *cls)
+{
+  //struct GNUNET_CLIENT_Connection *service_conn;
+  //static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
+  //  {&handle_reply, GNUNET_MESSAGE_TYPE_RPS_CS_REPLY, 0},
+  //  GNUNET_MQ_HANDLERS_END
+  //};
+  //struct cb_cls_pack *pack;
+  //struct GNUNET_MQ_Handle *mq;
+  //struct GNUNET_MQ_Envelope *ev;
+  //struct GNUNET_RPS_CS_RequestMessage *msg;
+  struct GNUNET_RPS_Handle *h;
+  struct GNUNET_RPS_Request_Handle *rh;
+
+  /* Connect to the service */
+  h = GNUNET_RPS_connect(cfg);
+  //h = GNUNET_new(struct GNUNET_RPS_Handle);
+  //h->conn = GNUNET_CLIENT_connect("rps", cfg);
+  //rh = GNUNET_new(struct GNUNET_RPS_Request_Handle);
+  ////pack = GNUNET_malloc(sizeof(struct cb_cls_pack));
+  ////pack->cb = ready_cb;
+  ////pack->cls = cls;
+  ////pack->service_conn = service_conn;
+  //mq = GNUNET_MQ_queue_for_connection_client(service_conn,
+  //                                           mq_handlers,
+  //                                           mq_error_handler, // TODO implement
+  //                                           h);
+
+  /* Send the request to the service */
+  rh = GNUNET_RPS_request_peers(h, n, ready_cb, cls);
+  //ev = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST);
+  //msg->num_peers = GNUNET_htonll(n);
+  //GNUNET_MQ_send(mq, ev);
+  //GNUNET_CLIENT_disconnect(service_conn);
+  //rh = GNUNET_new(struct GNUNET_RPS_Request_Handle);
+  GNUNET_RPS_disconnect(h);
+  return rh;
+}
+
+/**
+ * Connect to the rps service
+ */
+  struct GNUNET_RPS_Handle *
+GNUNET_RPS_connect( const struct GNUNET_CONFIGURATION_Handle *cfg )
+{
+  struct GNUNET_RPS_Handle *h;
+  //struct GNUNET_RPS_Request_Handle *rh;
+  static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
+    {&handle_reply, GNUNET_MESSAGE_TYPE_RPS_CS_REPLY, 0},
+    GNUNET_MQ_HANDLERS_END
+  };
+
+  h = GNUNET_new(struct GNUNET_RPS_Handle);
+  //h->cfg = GNUNET_new(struct GNUNET_CONFIGURATION_Handle);
+  //*h->cfg = *cfg;
+  h->cfg = cfg; // FIXME |^
+  h->conn = GNUNET_CLIENT_connect("rps", cfg);
+  h->mq = GNUNET_MQ_queue_for_connection_client(h->conn,
+                                                mq_handlers,
+                                                mq_error_handler, // TODO implement
+                                                h);
+
+
+  return h;
+}
+
+/**
+ * Request n random peers.
+ */
+  struct GNUNET_RPS_Request_Handle *
+GNUNET_RPS_request_peers (struct GNUNET_RPS_Handle *h, uint64_t n,
+                          GNUNET_RPS_NotifyReadyCB ready_cb,
+                          void *cls)
+{
+  struct GNUNET_RPS_Request_Handle *rh;
+  struct GNUNET_MQ_Envelope *ev;
+  struct GNUNET_RPS_CS_RequestMessage *msg;
+
+  // assert func != NULL
+  rh = GNUNET_new(struct GNUNET_RPS_Request_Handle);
+  rh->h = h;
+  rh->n = req_handlers_size; // TODO ntoh
+  rh->ready_cb = ready_cb;
+  rh->ready_cb_cls = cls;
+
+  GNUNET_array_append(req_handlers, req_handlers_size, *rh);
+  //memcpy(&req_handlers[req_handlers_size-1], rh, sizeof(struct GNUNET_RPS_Request_Handle));
+
+  ev = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST);
+  msg->num_peers = GNUNET_htonll(n);
+  msg->n = rh->n;
+  GNUNET_MQ_send(h->mq, ev);
+  return rh;
+}
+
+/**
+ * Cancle an issued request.
+ */
+  void
+GNUNET_RPS_request_cancel ( struct GNUNET_RPS_Request_Handle *rh )
+{
+  // TODO
+}
+
+/**
+ * Disconnect to the rps service
+ */
+  void
+GNUNET_RPS_disconnect ( struct GNUNET_RPS_Handle *h )
+{
+  if ( NULL != h->conn ) {
+    GNUNET_CLIENT_disconnect(h->conn);
+  }
+}
+
+
+/* end of rps_api.c */

+ 39 - 0
src/rps/test_rps.conf

@@ -0,0 +1,39 @@
+[rps]
+AUTOSTART = YES
+PREFIX = valgrind --log-file=/tmp/rps/valgrind!gnunet-service-rps!%p
+BINARY = gnunet-service-rps
+UNIXPATH = /tmp/gnunet-service-rps.sock
+HOME = $SERVICEHOME
+# PORT = 2106
+@UNIXONLY@ PORT = 2087
+
+# This is the timeinterval between the rounds
+ROUNDINTERVAL = 10 s
+
+# This is the 'estimate' in the beginning.
+# This determines the size of the peers we keep in memory
+# until we receive the first estimate from NSE.
+# Keep in mind, that (networksize)^(1/3) should be enough.
+# So, 50 is enough for a network of size 50^3 = 125000
+INITSIZE = 4
+
+ALPHA = 0.45
+
+
+[arm]
+DEFAULTSERVICES = core ats transport cadet nse rps
+
+[testbed]
+OPERATION_TIMEOUT = 60 s
+
+MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS = 1
+OVERLAY_TOPOLOGY = CLIQUE
+#SCALE_FREE_TOPOLOGY_CAP = 
+
+OVERLAY_RANDOM_LINKS = 5
+
+SETUP_TIMEOUT = 2 m
+
+
+[nse]
+WORKBITS = 0

+ 84 - 0
src/rps/test_rps_api.c

@@ -0,0 +1,84 @@
+/*
+     This file is part of GNUnet.
+     (C)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file rps/test_rps_api.c
+ * @brief testcase for rps_api.c
+ */
+#include <gnunet/platform.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "gnunet_rps_service.h"
+
+
+static int ok = 1;
+
+
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  ok = 0;
+}
+
+
+static int
+check ()
+{
+  char *const argv[] = { "test-rps-api", NULL };
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+  struct GNUNET_OS_Process *proc;
+  char *path = GNUNET_OS_get_libexec_binary_path ( "gnunet-service-rps");
+  if (NULL == path)
+  {
+  		fprintf (stderr, "Service executable not found `%s'\n", "gnunet-service-rps");
+  		return;
+  }
+
+  proc = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL,
+      NULL, NULL, path, "gnunet-service-rps", NULL);
+
+  GNUNET_free (path);
+  GNUNET_assert (NULL != proc);
+  GNUNET_PROGRAM_run (1, argv, "test-rps-api", "nohelp",
+                      options, &run, &ok);
+  if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+      ok = 1;
+    }
+  GNUNET_OS_process_wait (proc);
+  GNUNET_OS_process_destroy (proc);
+  return ok;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  GNUNET_log_setup ("test_statistics_api", 
+		    "WARNING",
+		    NULL);
+  return check ();
+}
+
+/* end of test_rps_api.c */

+ 244 - 0
src/rps/test_rps_multipeer.c

@@ -0,0 +1,244 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009, 2012 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
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file rps/test_rps_multipeer.c
+ * @brief Testcase for the random peer sampling service.  Starts
+ *        a peergroup with a given number of peers, then waits to
+ *        receive size pushes/pulls from each peer.  Expects to wait
+ *        for one message from each peer.
+ */
+#include"platform.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_rps_service.h"
+#include <time.h>
+
+
+/**
+ * How many peers do we start?
+ */
+#define NUM_PEERS 10
+
+/**
+ * How long do we run the test?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+
+/**
+ * Information we track for each peer.
+ */
+struct RPSPeer
+{
+  /**
+   * Handle for RPS connect operation.
+   */
+  struct GNUNET_TESTBED_Operation *op;
+
+  /**
+   * Handle to RPS service.
+   */
+  struct GNUNET_RPS_Handle *rps_handle;
+};
+
+
+/**
+ * Information for all the peers.
+ */
+static struct RPSPeer rps_peers[NUM_PEERS];
+
+/**
+ * Return value from 'main'.
+ */
+static int ok;
+
+
+/**
+ * Task run on timeout to shut everything down.
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  unsigned int i;
+
+  for (i=0;i<NUM_PEERS;i++)
+    GNUNET_TESTBED_operation_done (rps_peers[i].op);
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Callback to call when network size estimate is updated.
+ *
+ * @param cls closure
+ * @param timestamp server timestamp
+ * @param estimate the value of the current network size estimate
+ * @param std_dev standard deviation (rounded down to nearest integer)
+ *                of the size estimation values seen
+ *
+ */
+static void
+handle_reply (void *cls, uint64_t n, struct GNUNET_PeerIdentity *peers)
+{
+  //struct RPSPeer *peer = cls;
+
+  //FPRINTF (stderr,
+  //         "Received network size estimate from peer %u. logSize: %f std.dev. %f (%f/%u)\n",
+  //         (unsigned int) (peer - rps_peers),
+	//   estimate, std_dev,
+  //         GNUNET_NSE_log_estimate_to_n (estimate),
+	//   NUM_PEERS);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got peer %s\n", GNUNET_i2s(peers));
+  
+  ok = 0;
+}
+
+
+/**
+ * Callback to be called when RPS service connect operation is completed
+ *
+ * @param cls the callback closure from functions generating an operation
+ * @param op the operation that has been finished
+ * @param ca_result the RPS service handle returned from rps_connect_adapter
+ * @param emsg error message in case the operation has failed; will be NULL if
+ *          operation has executed successfully.
+ */
+static void
+rps_connect_complete_cb (void *cls,
+			 struct GNUNET_TESTBED_Operation *op,
+			 void *ca_result,
+			 const char *emsg)
+{
+  struct RPSPeer *peer = cls;
+  struct GNUNET_RPS_Handle *rps = ca_result;
+
+  GNUNET_assert (op == peer->op);
+  if (NULL != emsg)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+		  "Failed to connect to RPS service: %s\n",
+		  emsg);
+      ok = 1;
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+  peer->rps_handle = rps;
+  //sleep(50);
+  GNUNET_RPS_request_peers(rps, 1, handle_reply, NULL);
+  GNUNET_RPS_request_peers(rps, 1, handle_reply, NULL);
+  //sleep(10000);
+  //GNUNET_RPS_request_peers(rps, 1, handle_reply, NULL);
+  //sleep(10000);
+  //GNUNET_RPS_request_peers(rps, 1, handle_reply, NULL);
+  //sleep(10000);
+  //GNUNET_RPS_request_peers(rps, 1, handle_reply, NULL);
+}
+
+
+/**
+ * Adapter function called to establish a connection to
+ * the RPS service.
+ *
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+rps_connect_adapter (void *cls,
+		     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  return GNUNET_RPS_connect (cfg);
+}
+
+
+/**
+ * Adapter function called to destroy connection to
+ * RPS service.
+ *
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+rps_disconnect_adapter (void *cls,
+			void *op_result)
+{
+  struct GNUNET_RPS_Handle *h = op_result;
+  GNUNET_RPS_disconnect (h);
+}
+
+
+/**
+ * Actual "main" function for the testcase.
+ *
+ * @param cls closure
+ * @param h the run handle
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ * @param links_succeeded the number of overlay link connection attempts that
+ *          succeeded
+ * @param links_failed the number of overlay link connection attempts that
+ *          failed
+ */
+static void
+run (void *cls,
+     struct GNUNET_TESTBED_RunHandle *h,
+     unsigned int num_peers,
+     struct GNUNET_TESTBED_Peer **peers,
+     unsigned int links_succeeded,
+     unsigned int links_failed)
+{
+  unsigned int i;
+
+  GNUNET_assert (NUM_PEERS == num_peers);
+  for (i=0;i<num_peers;i++)
+    rps_peers[i].op = GNUNET_TESTBED_service_connect (&rps_peers[i],
+						      peers[i],
+						      "rps",
+						      &rps_connect_complete_cb,
+						      &rps_peers[i],
+						      &rps_connect_adapter,
+						      &rps_disconnect_adapter,
+						      &rps_peers[i]);
+  GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
+}
+
+
+/**
+ * Entry point for the testcase, sets up the testbed.
+ *
+ * @param argc unused
+ * @param argv unused
+ * @return 0 on success
+ */
+int
+main (int argc, char *argv[])
+{
+  ok = 1;
+  (void) GNUNET_TESTBED_test_run ("test-rps-multipeer",
+                                  "test_rps.conf",
+                                  NUM_PEERS,
+                                  0, NULL, NULL,
+                                  &run, NULL);
+  return ok;
+}
+
+/* end of test_rps_multipeer.c */