-doxygen and stylistic fixes
[oweals/gnunet.git] / src / rps / gnunet-service-rps_sampler.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file rps/gnunet-service-rps_sampler.c
23  * @brief sampler implementation
24  * @author Julius Bünger
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "rps.h"
29
30 #include "gnunet-service-rps_sampler.h"
31
32 #include <math.h>
33 #include <inttypes.h>
34
35 #define LOG(kind, ...) GNUNET_log_from(kind,"rps-sampler",__VA_ARGS__)
36
37 // multiple 'clients'?
38
39 // TODO check for overflows
40
41 // TODO align message structs
42
43 // hist_size_init, hist_size_max
44
45 /***********************************************************************
46  * WARNING: This section needs to be reviewed regarding the use of
47  * functions providing (pseudo)randomness!
48 ***********************************************************************/
49
50 // TODO care about invalid input of the caller (size 0 or less...)
51
52 enum RPS_SamplerEmpty
53 {
54   NOT_EMPTY = 0x0,
55       EMPTY = 0x1
56 };
57
58 /**
59  * A sampler element sampling one PeerID at a time.
60  */
61 struct RPS_SamplerElement
62 {
63   /**
64    * Min-wise linear permutation used by this sampler.
65    *
66    * This is an key later used by a hmac.
67    */
68   struct GNUNET_CRYPTO_AuthKey auth_key;
69
70   /**
71    * The PeerID this sampler currently samples.
72    */
73   struct GNUNET_PeerIdentity peer_id;
74
75   /**
76    * The according hash value of this PeerID.
77    */
78   struct GNUNET_HashCode peer_id_hash;
79
80
81   /**
82    * Time of last request.
83    */
84   struct GNUNET_TIME_Absolute last_client_request;
85
86   /**
87    * Flag that indicates that we are not holding a valid PeerID right now.
88    */
89   enum RPS_SamplerEmpty is_empty;
90
91   /**
92    * 'Birth'
93    */
94   struct GNUNET_TIME_Absolute birth;
95
96   /**
97    * How many times a PeerID was put in this sampler.
98    */
99   uint32_t num_peers;
100
101   /**
102    * How many times this sampler changed the peer_id.
103    */
104   uint32_t num_change;
105 };
106
107
108 /**
109  * Sampler with its own array of SamplerElements
110  */
111 struct RPS_Sampler
112 {
113   /**
114    * Number of sampler elements we hold.
115    */
116   unsigned int sampler_size;
117   //size_t size;
118
119   /**
120    * All Samplers in one array.
121    */
122   struct RPS_SamplerElement **sampler_elements;
123
124   /**
125    * Max time a round takes
126    *
127    * Used in the context of RPS
128    */
129   struct GNUNET_TIME_Relative max_round_interval;
130 };
131
132 /**
133  * Closure to _get_n_rand_peers_ready_cb()
134  */
135 struct NRandPeersReadyCls
136 {
137   /**
138    * Number of peers we are waiting for.
139    */
140   uint32_t num_peers;
141
142   /**
143    * Number of peers we currently have.
144    */
145   uint32_t cur_num_peers;
146
147   /**
148    * Pointer to the array holding the ids.
149    */
150   struct GNUNET_PeerIdentity *ids;
151
152   /**
153    * Callback to be called when all ids are available.
154    */
155   RPS_sampler_n_rand_peers_ready_cb callback;
156
157   /**
158    * Closure given to the callback
159    */
160   void *cls;
161 };
162
163 /**
164  * Callback that is called from _get_rand_peer() when the PeerID is ready.
165  *
166  * @param cls the closure given alongside this function.
167  * @param id the PeerID that was returned
168  */
169 typedef void
170 (*RPS_sampler_rand_peer_ready_cont) (void *cls,
171         const struct GNUNET_PeerIdentity *id);
172
173 /**
174  * Closure for #sampler_get_rand_peer()
175  */
176 struct GetPeerCls
177 {
178   /**
179    * DLL
180    */
181   struct GetPeerCls *next;
182
183   /**
184    * DLL
185    */
186   struct GetPeerCls *prev;
187
188   /**
189    * The sampler this function operates on.
190    */
191   struct RPS_Sampler *sampler;
192
193   /**
194    * The task for this function.
195    */
196   struct GNUNET_SCHEDULER_Task *get_peer_task;
197
198   /**
199    * The callback
200    */
201   RPS_sampler_rand_peer_ready_cont cont;
202
203   /**
204    * The closure to the callback @e cont
205    */
206   void *cont_cls;
207
208   /**
209    * The address of the id to be stored at
210    */
211   struct GNUNET_PeerIdentity *id;
212 };
213
214
215 ///**
216 // * Global sampler variable.
217 // */
218 //struct RPS_Sampler *sampler;
219
220
221 /**
222  * The minimal size for the extended sampler elements.
223  */
224 static size_t min_size;
225
226 /**
227  * The maximal size the extended sampler elements should grow to.
228  */
229 static size_t max_size;
230
231 /**
232  * The size the extended sampler elements currently have.
233  */
234 //static size_t extra_size;
235
236 /**
237  * Inedex to the sampler element that is the next to be returned
238  */
239 static uint32_t client_get_index;
240
241
242 /** FIXME document */
243 static struct GetPeerCls *gpc_head;
244 static struct GetPeerCls *gpc_tail;
245
246
247 /**
248  * Callback to _get_rand_peer() used by _get_n_rand_peers().
249  *
250  * Checks whether all n peers are available. If they are,
251  * give those back.
252  */
253 static void
254 check_n_peers_ready (void *cls,
255     const struct GNUNET_PeerIdentity *id)
256 {
257   struct NRandPeersReadyCls *n_peers_cls = cls;
258
259   n_peers_cls->cur_num_peers++;
260   LOG (GNUNET_ERROR_TYPE_DEBUG,
261       "Got %" PRIX32 ". of %" PRIX32 " peers\n",
262       n_peers_cls->cur_num_peers, n_peers_cls->num_peers);
263
264   if (n_peers_cls->num_peers == n_peers_cls->cur_num_peers)
265   { /* All peers are ready -- return those to the client */
266     GNUNET_assert (NULL != n_peers_cls->callback);
267
268     LOG (GNUNET_ERROR_TYPE_DEBUG,
269         "returning %" PRIX32 " peers to the client\n",
270         n_peers_cls->num_peers);
271     n_peers_cls->callback (n_peers_cls->cls, n_peers_cls->ids, n_peers_cls->num_peers);
272
273     GNUNET_free (n_peers_cls);
274   }
275 }
276
277
278 /**
279  * Reinitialise a previously initialised sampler element.
280  *
281  * @param sampler pointer to the memory that keeps the value.
282  */
283   static void
284 RPS_sampler_elem_reinit (struct RPS_SamplerElement *sampler_el)
285 {
286   sampler_el->is_empty = EMPTY;
287
288   // I guess I don't need to call GNUNET_CRYPTO_hmac_derive_key()...
289   GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_STRONG,
290                              &(sampler_el->auth_key.key),
291                              GNUNET_CRYPTO_HASH_LENGTH);
292
293   sampler_el->last_client_request = GNUNET_TIME_UNIT_FOREVER_ABS;
294
295   sampler_el->birth = GNUNET_TIME_absolute_get ();
296   sampler_el->num_peers = 0;
297   sampler_el->num_change = 0;
298 }
299
300
301 /**
302  * (Re)Initialise given Sampler with random min-wise independent function.
303  *
304  * In this implementation this means choosing an auth_key for later use in
305  * a hmac at random.
306  *
307  * @return a newly created RPS_SamplerElement which currently holds no id.
308  */
309   struct RPS_SamplerElement *
310 RPS_sampler_elem_create (void)
311 {
312   struct RPS_SamplerElement *s;
313
314   s = GNUNET_new (struct RPS_SamplerElement);
315
316   RPS_sampler_elem_reinit (s);
317   LOG (GNUNET_ERROR_TYPE_DEBUG, "initialised with empty PeerID\n");
318
319   return s;
320 }
321
322
323 /**
324  * Input an PeerID into the given sampler element.
325  *
326  * @param sampler the sampler the @a s_elem belongs to.
327  *                Needed to know the
328  */
329 static void
330 RPS_sampler_elem_next (struct RPS_SamplerElement *s_elem,
331                        struct RPS_Sampler *sampler,
332                        const struct GNUNET_PeerIdentity *other)
333 {
334   struct GNUNET_HashCode other_hash;
335
336   s_elem->num_peers++;
337
338   if (0 == GNUNET_CRYPTO_cmp_peer_identity (other, &(s_elem->peer_id)))
339   {
340     LOG (GNUNET_ERROR_TYPE_DEBUG, "         Got PeerID %s\n",
341         GNUNET_i2s (other));
342     LOG (GNUNET_ERROR_TYPE_DEBUG, "Have already PeerID %s\n",
343         GNUNET_i2s (&(s_elem->peer_id)));
344   }
345   else
346   {
347     GNUNET_CRYPTO_hmac(&s_elem->auth_key,
348         other,
349         sizeof(struct GNUNET_PeerIdentity),
350         &other_hash);
351
352     if (EMPTY == s_elem->is_empty)
353     {
354       LOG (GNUNET_ERROR_TYPE_DEBUG,
355            "Got PeerID %s; Simply accepting (was empty previously).\n",
356            GNUNET_i2s(other));
357       s_elem->peer_id = *other;
358       s_elem->peer_id_hash = other_hash;
359
360       s_elem->num_change++;
361     }
362     else if (0 > GNUNET_CRYPTO_hash_cmp (&other_hash, &s_elem->peer_id_hash))
363     {
364       LOG (GNUNET_ERROR_TYPE_DEBUG, "           Got PeerID %s\n",
365           GNUNET_i2s (other));
366       LOG (GNUNET_ERROR_TYPE_DEBUG, "Discarding old PeerID %s\n",
367           GNUNET_i2s (&s_elem->peer_id));
368
369       s_elem->num_change++;
370     }
371     else
372     {
373       LOG (GNUNET_ERROR_TYPE_DEBUG, "        Got PeerID %s\n",
374           GNUNET_i2s (other));
375       LOG (GNUNET_ERROR_TYPE_DEBUG, "Keeping old PeerID %s\n",
376           GNUNET_i2s (&s_elem->peer_id));
377     }
378   }
379   s_elem->is_empty = NOT_EMPTY;
380 }
381
382
383 /**
384  * Get the size of the sampler.
385  *
386  * @param sampler the sampler to return the size of.
387  * @return the size of the sampler
388  */
389 unsigned int
390 RPS_sampler_get_size (struct RPS_Sampler *sampler)
391 {
392   return sampler->sampler_size;
393 }
394
395
396 /**
397  * Grow or shrink the size of the sampler.
398  *
399  * @param sampler the sampler to resize.
400  * @param new_size the new size of the sampler
401  */
402 static void
403 sampler_resize (struct RPS_Sampler *sampler, unsigned int new_size)
404 {
405   unsigned int old_size;
406   uint32_t i;
407
408   // TODO check min and max size
409
410   old_size = sampler->sampler_size;
411
412   if (old_size > new_size)
413   { /* Shrinking */
414     /* Temporary store those to properly call the removeCB on those later */
415
416     LOG (GNUNET_ERROR_TYPE_DEBUG, "Shrinking sampler %d -> %d\n", old_size, new_size);
417     GNUNET_array_grow (sampler->sampler_elements, sampler->sampler_size, new_size);
418     LOG (GNUNET_ERROR_TYPE_DEBUG,
419         "sampler->sampler_elements now points to %p\n",
420         sampler->sampler_elements);
421
422   }
423   else if (old_size < new_size)
424   { /* Growing */
425     LOG (GNUNET_ERROR_TYPE_DEBUG, "Growing sampler %d -> %d\n", old_size, new_size);
426     GNUNET_array_grow (sampler->sampler_elements, sampler->sampler_size, new_size);
427     LOG (GNUNET_ERROR_TYPE_DEBUG,
428         "sampler->sampler_elements now points to %p\n",
429         sampler->sampler_elements);
430
431     for ( i = old_size ; i < new_size ; i++ )
432     { /* Add new sampler elements */
433       sampler->sampler_elements[i] = RPS_sampler_elem_create ();
434       LOG (GNUNET_ERROR_TYPE_DEBUG,
435           "Added %" PRIX32 ". sampler, now pointing to %p, contains %s\n",
436           i, &sampler->sampler_elements[i], GNUNET_i2s (&sampler->sampler_elements[i]->peer_id));
437     }
438   }
439   else
440   {
441     LOG (GNUNET_ERROR_TYPE_DEBUG, "Size remains the same -- nothing to do\n");
442     return;
443   }
444
445   GNUNET_assert (sampler->sampler_size == new_size);
446   LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished growing/shrinking.\n"); // remove
447 }
448
449
450 /**
451  * Grow or shrink the size of the sampler.
452  *
453  * @param sampler the sampler to resize.
454  * @param new_size the new size of the sampler
455  */
456 void
457 RPS_sampler_resize (struct RPS_Sampler *sampler, unsigned int new_size)
458 {
459   GNUNET_assert (0 < new_size);
460   sampler_resize (sampler, new_size);
461 }
462
463
464 /**
465  * Empty the sampler.
466  *
467  * @param sampler the sampler to empty.
468  * @param new_size the new size of the sampler
469  */
470 static void
471 sampler_empty (struct RPS_Sampler *sampler)
472 {
473   sampler_resize (sampler, 0);
474 }
475
476
477 /**
478  * Initialise a tuple of sampler elements.
479  *
480  * @param init_size the size the sampler is initialised with
481  * @param ins_cb the callback that will be called on every PeerID that is
482  *               newly inserted into a sampler element
483  * @param ins_cls the closure given to #ins_cb
484  * @param rem_cb the callback that will be called on every PeerID that is
485  *               removed from a sampler element
486  * @param rem_cls the closure given to #rem_cb
487  * @return a handle to a sampler that consists of sampler elements.
488  */
489 struct RPS_Sampler *
490 RPS_sampler_init (size_t init_size,
491     struct GNUNET_TIME_Relative max_round_interval)
492 {
493   struct RPS_Sampler *sampler;
494   //uint32_t i;
495
496   /* Initialise context around extended sampler */
497   min_size = 10; // TODO make input to _samplers_init()
498   max_size = 1000; // TODO make input to _samplers_init()
499
500   sampler = GNUNET_new (struct RPS_Sampler);
501   sampler->sampler_size = 0;
502   sampler->sampler_elements = NULL;
503   sampler->max_round_interval = max_round_interval;
504   //sampler->sampler_elements = GNUNET_new_array(init_size, struct GNUNET_PeerIdentity);
505   //GNUNET_array_grow (sampler->sampler_elements, sampler->sampler_size, min_size);
506   RPS_sampler_resize (sampler, init_size);
507
508   client_get_index = 0;
509
510   //GNUNET_assert (init_size == sampler->sampler_size);
511   return sampler;
512 }
513
514
515 /**
516  * A fuction to update every sampler in the given list
517  *
518  * @param sampler the sampler to update.
519  * @param id the PeerID that is put in the sampler
520  */
521   void
522 RPS_sampler_update (struct RPS_Sampler *sampler,
523                     const struct GNUNET_PeerIdentity *id)
524 {
525   uint32_t i;
526
527   for ( i = 0 ; i < sampler->sampler_size ; i++ )
528     RPS_sampler_elem_next (sampler->sampler_elements[i],
529                            sampler,
530                            id);
531 }
532
533
534 /**
535  * Reinitialise all previously initialised sampler elements with the given value.
536  *
537  * Used to get rid of a PeerID.
538  *
539  * @param sampler the sampler to reinitialise a sampler element in.
540  * @param id the id of the sampler elements to update.
541  */
542   void
543 RPS_sampler_reinitialise_by_value (struct RPS_Sampler *sampler,
544                                    const struct GNUNET_PeerIdentity *id)
545 {
546   uint32_t i;
547
548   for ( i = 0 ; i < sampler->sampler_size ; i++ )
549   {
550     if ( 0 == GNUNET_CRYPTO_cmp_peer_identity(id, &(sampler->sampler_elements[i]->peer_id)) )
551     {
552       LOG (GNUNET_ERROR_TYPE_DEBUG, "Reinitialising sampler\n");
553       RPS_sampler_elem_reinit (sampler->sampler_elements[i]);
554     }
555   }
556 }
557
558
559 /**
560  * Get one random peer out of the sampled peers.
561  *
562  * We might want to reinitialise this sampler after giving the
563  * corrsponding peer to the client.
564  * Only used internally
565  */
566 static void
567 sampler_get_rand_peer2 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
568 {
569   struct GetPeerCls *gpc = cls;
570   uint32_t r_index;
571
572   gpc->get_peer_task = NULL;
573   GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, gpc);
574   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
575     return;
576
577   /**;
578    * Choose the r_index of the peer we want to return
579    * at random from the interval of the gossip list
580    */
581   r_index = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
582       gpc->sampler->sampler_size);
583
584   if ( EMPTY == gpc->sampler->sampler_elements[r_index]->is_empty )
585   {
586     gpc->get_peer_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
587                                                                    GNUNET_TIME_UNIT_SECONDS,
588                                                                    .1),
589                                                        &sampler_get_rand_peer2,
590                                                        cls);
591     return;
592   }
593
594   *gpc->id = gpc->sampler->sampler_elements[r_index]->peer_id;
595
596   gpc->cont (gpc->cont_cls, gpc->id);
597   GNUNET_free (gpc);
598 }
599
600
601 /**
602  * Get one random peer out of the sampled peers.
603  *
604  * We might want to reinitialise this sampler after giving the
605  * corrsponding peer to the client.
606  */
607 static void
608 sampler_get_rand_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
609 {
610   struct GetPeerCls *gpc = cls;
611   struct GNUNET_PeerIdentity tmp_id;
612   unsigned int empty_flag;
613   struct RPS_SamplerElement *s_elem;
614   struct GNUNET_TIME_Relative last_request_diff;
615   uint32_t tmp_client_get_index;
616
617   gpc->get_peer_task = NULL;
618   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
619     return;
620
621   LOG (GNUNET_ERROR_TYPE_DEBUG, "Single peer was requested\n");
622
623
624   /* Store the next #client_get_index to check whether we cycled over the whole list */
625   if (0 < client_get_index)
626     tmp_client_get_index = client_get_index - 1;
627   else
628     tmp_client_get_index = gpc->sampler->sampler_size - 1;
629
630   LOG (GNUNET_ERROR_TYPE_DEBUG,
631       "sched for later if index reaches %" PRIX32 " (sampler size: %" PRIX32 ").\n",
632       tmp_client_get_index, gpc->sampler->sampler_size);
633
634   do
635   { /* Get first non empty sampler */
636     if (tmp_client_get_index == client_get_index)
637     { /* We once cycled over the whole list */
638       LOG (GNUNET_ERROR_TYPE_DEBUG, "reached tmp_index %" PRIX32 ".\n",
639            client_get_index);
640       GNUNET_assert (NULL == gpc->get_peer_task);
641       gpc->get_peer_task =
642         GNUNET_SCHEDULER_add_delayed (gpc->sampler->max_round_interval,
643                                       &sampler_get_rand_peer,
644                                       cls);
645       return;
646     }
647
648     tmp_id = gpc->sampler->sampler_elements[client_get_index]->peer_id;
649     empty_flag = gpc->sampler->sampler_elements[client_get_index]->is_empty;
650     RPS_sampler_elem_reinit (gpc->sampler->sampler_elements[client_get_index]);
651     if (EMPTY != empty_flag)
652       RPS_sampler_elem_next (gpc->sampler->sampler_elements[client_get_index],
653                              gpc->sampler,
654                              &tmp_id);
655
656     /* Cycle the #client_get_index one step further */
657     if ( client_get_index == gpc->sampler->sampler_size - 1 )
658       client_get_index = 0;
659     else
660       client_get_index++;
661
662     LOG (GNUNET_ERROR_TYPE_DEBUG, "incremented index to %" PRIX32 ".\n",
663          client_get_index);
664   } while (EMPTY == gpc->sampler->sampler_elements[client_get_index]->is_empty);
665
666   s_elem = gpc->sampler->sampler_elements[client_get_index];
667   *gpc->id = s_elem->peer_id;
668
669   /* Check whether we may use this sampler to give it back to the client */
670   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != s_elem->last_client_request.abs_value_us)
671   {
672     last_request_diff =
673       GNUNET_TIME_absolute_get_difference (s_elem->last_client_request,
674                                            GNUNET_TIME_absolute_get ());
675     /* We're not going to give it back now if it was
676      * already requested by a client this round */
677     if (last_request_diff.rel_value_us < gpc->sampler->max_round_interval.rel_value_us)
678     {
679       LOG (GNUNET_ERROR_TYPE_DEBUG,
680           "Last client request on this sampler was less than max round interval ago -- scheduling for later\n");
681       ///* How many time remains untile the next round has started? */
682       //inv_last_request_diff =
683       //  GNUNET_TIME_absolute_get_difference (last_request_diff,
684       //                                       sampler->max_round_interval);
685       // add a little delay
686       /* Schedule it one round later */
687       GNUNET_assert (NULL == gpc->get_peer_task);
688       gpc->get_peer_task =
689         GNUNET_SCHEDULER_add_delayed (gpc->sampler->max_round_interval,
690                                       &sampler_get_rand_peer,
691                                       cls);
692       return;
693     }
694     // TODO add other reasons to wait here
695   }
696
697   s_elem->last_client_request = GNUNET_TIME_absolute_get ();
698
699   GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, gpc);
700   gpc->cont (gpc->cont_cls, gpc->id);
701   GNUNET_free (gpc);
702 }
703
704
705 /**
706  * Get n random peers out of the sampled peers.
707  *
708  * We might want to reinitialise this sampler after giving the
709  * corrsponding peer to the client.
710  * Random with or without consumption?
711  *
712  * @param sampler the sampler to get peers from.
713  * @param cb callback that will be called once the ids are ready.
714  * @param cls closure given to @a cb
715  * @param for_client #GNUNET_YES if result is used for client,
716  *                   #GNUNET_NO if used internally
717  * @param num_peers the number of peers requested
718  */
719   void
720 RPS_sampler_get_n_rand_peers (struct RPS_Sampler *sampler,
721                               RPS_sampler_n_rand_peers_ready_cb cb,
722                               void *cls, uint32_t num_peers, int for_client)
723 {
724   GNUNET_assert (0 != sampler->sampler_size);
725
726   // TODO check if we have too much (distinct) sampled peers
727   uint32_t i;
728   struct NRandPeersReadyCls *cb_cls;
729   struct GetPeerCls *gpc;
730
731   cb_cls = GNUNET_new (struct NRandPeersReadyCls);
732   cb_cls->num_peers = num_peers;
733   cb_cls->cur_num_peers = 0;
734   cb_cls->ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
735   cb_cls->callback = cb;
736   cb_cls->cls = cls;
737
738   LOG (GNUNET_ERROR_TYPE_DEBUG,
739       "Scheduling requests for %" PRIX32 " peers\n", num_peers);
740
741   for ( i = 0 ; i < num_peers ; i++ )
742   {
743     gpc = GNUNET_new (struct GetPeerCls);
744     gpc->sampler = sampler;
745     gpc->cont = check_n_peers_ready;
746     gpc->cont_cls = cb_cls;
747     gpc->id = &cb_cls->ids[i];
748
749     // maybe add a little delay
750     if (GNUNET_YES == for_client)
751       gpc->get_peer_task = GNUNET_SCHEDULER_add_now (&sampler_get_rand_peer, gpc);
752     else if (GNUNET_NO == for_client)
753       gpc->get_peer_task = GNUNET_SCHEDULER_add_now (&sampler_get_rand_peer2, gpc);
754     else
755       GNUNET_assert (0);
756
757     GNUNET_CONTAINER_DLL_insert (gpc_head, gpc_tail, gpc);
758   }
759 }
760
761
762 /**
763  * Counts how many Samplers currently hold a given PeerID.
764  *
765  * @param sampler the sampler to count ids in.
766  * @param id the PeerID to count.
767  *
768  * @return the number of occurrences of id.
769  */
770   uint32_t
771 RPS_sampler_count_id (struct RPS_Sampler *sampler,
772                       const struct GNUNET_PeerIdentity *id)
773 {
774   uint32_t count;
775   uint32_t i;
776
777   count = 0;
778   for ( i = 0 ; i < sampler->sampler_size ; i++ )
779   {
780     if ( 0 == GNUNET_CRYPTO_cmp_peer_identity (&sampler->sampler_elements[i]->peer_id, id)
781         && EMPTY != sampler->sampler_elements[i]->is_empty)
782       count++;
783   }
784   return count;
785 }
786
787
788 /**
789  * Cleans the sampler.
790  */
791   void
792 RPS_sampler_destroy (struct RPS_Sampler *sampler)
793 {
794   struct GetPeerCls *i;
795
796   for (i = gpc_head; NULL != i; i = gpc_head)
797   {
798     GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, i);
799     GNUNET_SCHEDULER_cancel (i->get_peer_task);
800     GNUNET_free (i);
801   }
802
803   sampler_empty (sampler);
804   GNUNET_free (sampler);
805 }
806
807 /* end of gnunet-service-rps.c */