summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore12
-rw-r--r--configure.ac3
-rw-r--r--pkgconfig/Makefile.am2
-rw-r--r--pkgconfig/gnunetrps.pc.in12
-rw-r--r--src/Makefile.am1
-rw-r--r--src/include/gnunet_protocols.h39
-rw-r--r--src/include/gnunet_rps_service.h83
-rw-r--r--src/rps/Makefile.am76
-rw-r--r--src/rps/gnunet-rps.c71
-rw-r--r--src/rps/gnunet-service-rps.c1382
-rw-r--r--src/rps/rps.conf.in7
-rw-r--r--src/rps/rps.h139
-rw-r--r--src/rps/rps_api.c279
-rw-r--r--src/rps/test_rps.conf39
-rw-r--r--src/rps/test_rps_api.c84
-rw-r--r--src/rps/test_rps_multipeer.c244
16 files changed, 2472 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 1cef035c4..e80a99663 100644
--- a/.gitignore
+++ b/.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
diff --git a/configure.ac b/configure.ac
index ae7e04394..9c0bdc1b1 100644
--- a/configure.ac
+++ b/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
diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am
index ac40906cd..547755c12 100644
--- a/pkgconfig/Makefile.am
+++ b/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 \
diff --git a/pkgconfig/gnunetrps.pc.in b/pkgconfig/gnunetrps.pc.in
new file mode 100644
index 000000000..94042e8eb
--- /dev/null
+++ b/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}
diff --git a/src/Makefile.am b/src/Makefile.am
index 18f8aeef2..8efb7afe6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@ if HAVE_EXPERIMENTAL
env \
psycstore \
psyc \
+ rps \
social \
$(CONSENSUS) \
$(SECRETSHARING) \
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 5a2b644be..747a252ff 100644
--- a/src/include/gnunet_protocols.h
+++ b/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
*/
/**
diff --git a/src/include/gnunet_rps_service.h b/src/include/gnunet_rps_service.h
new file mode 100644
index 000000000..dc822b8f1
--- /dev/null
+++ b/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
diff --git a/src/rps/Makefile.am b/src/rps/Makefile.am
new file mode 100644
index 000000000..f6c31b107
--- /dev/null
+++ b/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
+
diff --git a/src/rps/gnunet-rps.c b/src/rps/gnunet-rps.c
new file mode 100644
index 000000000..7a4f75d6f
--- /dev/null
+++ b/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 */
diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c
new file mode 100644
index 000000000..6d96f5486
--- /dev/null
+++ b/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 */
diff --git a/src/rps/rps.conf.in b/src/rps/rps.conf.in
new file mode 100644
index 000000000..bd64791be
--- /dev/null
+++ b/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
+
diff --git a/src/rps/rps.h b/src/rps/rps.h
new file mode 100644
index 000000000..46c8ab0bb
--- /dev/null
+++ b/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
diff --git a/src/rps/rps_api.c b/src/rps/rps_api.c
new file mode 100644
index 000000000..ba8a594b7
--- /dev/null
+++ b/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 */
diff --git a/src/rps/test_rps.conf b/src/rps/test_rps.conf
new file mode 100644
index 000000000..f27bf0717
--- /dev/null
+++ b/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 \ No newline at end of file
diff --git a/src/rps/test_rps_api.c b/src/rps/test_rps_api.c
new file mode 100644
index 000000000..1772594ac
--- /dev/null
+++ b/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 */
diff --git a/src/rps/test_rps_multipeer.c b/src/rps/test_rps_multipeer.c
new file mode 100644
index 000000000..5c90e393d
--- /dev/null
+++ b/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 */