-optical changes
[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    * The file name this sampler element should log to
108    */
109   #ifdef TO_FILE
110   char *file_name;
111   #endif /* TO_FILE */
112 };
113
114
115 /**
116  * Sampler with its own array of SamplerElements
117  */
118 struct RPS_Sampler
119 {
120   /**
121    * Number of sampler elements we hold.
122    */
123   unsigned int sampler_size;
124   //size_t size;
125
126   /**
127    * All Samplers in one array.
128    */
129   struct RPS_SamplerElement **sampler_elements;
130
131   /**
132    * Max time a round takes
133    *
134    * Used in the context of RPS
135    */
136   struct GNUNET_TIME_Relative max_round_interval;
137
138   #ifdef TO_FILE
139   /**
140    * File name to log to
141    */
142   char *file_name;
143   #endif /* TO_FILE */
144 };
145
146 /**
147  * Closure to _get_n_rand_peers_ready_cb()
148  */
149 struct NRandPeersReadyCls
150 {
151   /**
152    * Number of peers we are waiting for.
153    */
154   uint32_t num_peers;
155
156   /**
157    * Number of peers we currently have.
158    */
159   uint32_t cur_num_peers;
160
161   /**
162    * Pointer to the array holding the ids.
163    */
164   struct GNUNET_PeerIdentity *ids;
165
166   /**
167    * Callback to be called when all ids are available.
168    */
169   RPS_sampler_n_rand_peers_ready_cb callback;
170
171   /**
172    * Closure given to the callback
173    */
174   void *cls;
175 };
176
177 /**
178  * Callback that is called from _get_rand_peer() when the PeerID is ready.
179  *
180  * @param cls the closure given alongside this function.
181  * @param id the PeerID that was returned
182  */
183 typedef void
184 (*RPS_sampler_rand_peer_ready_cont) (void *cls,
185         const struct GNUNET_PeerIdentity *id);
186
187 /**
188  * Closure for #sampler_get_rand_peer()
189  */
190 struct GetPeerCls
191 {
192   /**
193    * DLL
194    */
195   struct GetPeerCls *next;
196
197   /**
198    * DLL
199    */
200   struct GetPeerCls *prev;
201
202   /**
203    * The sampler this function operates on.
204    */
205   struct RPS_Sampler *sampler;
206
207   /**
208    * The task for this function.
209    */
210   struct GNUNET_SCHEDULER_Task *get_peer_task;
211
212   /**
213    * The callback
214    */
215   RPS_sampler_rand_peer_ready_cont cont;
216
217   /**
218    * The closure to the callback @e cont
219    */
220   void *cont_cls;
221
222   /**
223    * The address of the id to be stored at
224    */
225   struct GNUNET_PeerIdentity *id;
226 };
227
228
229 ///**
230 // * Global sampler variable.
231 // */
232 //struct RPS_Sampler *sampler;
233
234
235 /**
236  * The minimal size for the extended sampler elements.
237  */
238 static size_t min_size;
239
240 /**
241  * The maximal size the extended sampler elements should grow to.
242  */
243 static size_t max_size;
244
245 /**
246  * The size the extended sampler elements currently have.
247  */
248 //static size_t extra_size;
249
250 /**
251  * Inedex to the sampler element that is the next to be returned
252  */
253 static uint32_t client_get_index;
254
255
256 #ifdef TO_FILE
257 /**
258  * This function is used to facilitate writing important information to disk
259  */
260 #define to_file(file_name, ...) do {char tmp_buf[512];\
261   int size;\
262   size = GNUNET_snprintf(tmp_buf,sizeof(tmp_buf),__VA_ARGS__);\
263   if (0 > size)\
264     LOG (GNUNET_ERROR_TYPE_WARNING,\
265          "Failed to create tmp_buf\n");\
266   else\
267     to_file_(file_name,tmp_buf);\
268 } while (0);
269
270 static void
271 to_file_ (char *file_name, char *line)
272 {
273   struct GNUNET_DISK_FileHandle *f;
274   char output_buffer[512];
275   //size_t size;
276   int size;
277   size_t size2;
278
279
280   if (NULL == (f = GNUNET_DISK_file_open (file_name,
281                                           GNUNET_DISK_OPEN_APPEND |
282                                           GNUNET_DISK_OPEN_WRITE |
283                                           GNUNET_DISK_OPEN_CREATE,
284                                           GNUNET_DISK_PERM_USER_WRITE)))
285   {
286     LOG (GNUNET_ERROR_TYPE_WARNING,
287          "Not able to open file %s\n",
288          file_name);
289     return;
290   }
291   size = GNUNET_snprintf (output_buffer,
292                           sizeof (output_buffer),
293                           "%llu %s\n",
294                           GNUNET_TIME_absolute_get ().abs_value_us,
295                           line);
296   if (0 > size)
297   {
298     LOG (GNUNET_ERROR_TYPE_WARNING,
299          "Failed to write string to buffer (size: %i)\n",
300          size);
301     return;
302   }
303
304   size2 = GNUNET_DISK_file_write (f, output_buffer, size);
305   if (size != size2)
306   {
307     LOG (GNUNET_ERROR_TYPE_WARNING,
308          "Unable to write to file! (Size: %u, size2: %u)\n",
309          size,
310          size2);
311     return;
312   }
313
314   if (GNUNET_YES != GNUNET_DISK_file_close (f))
315     LOG (GNUNET_ERROR_TYPE_WARNING,
316          "Unable to close file\n");
317 }
318 #endif /* TO_FILE */
319
320
321 /** FIXME document */
322 static struct GetPeerCls *gpc_head;
323 static struct GetPeerCls *gpc_tail;
324
325
326 /**
327  * Callback to _get_rand_peer() used by _get_n_rand_peers().
328  *
329  * Checks whether all n peers are available. If they are,
330  * give those back.
331  */
332 static void
333 check_n_peers_ready (void *cls,
334     const struct GNUNET_PeerIdentity *id)
335 {
336   struct NRandPeersReadyCls *n_peers_cls = cls;
337
338   n_peers_cls->cur_num_peers++;
339   LOG (GNUNET_ERROR_TYPE_DEBUG,
340       "Got %" PRIX32 ". of %" PRIX32 " peers\n",
341       n_peers_cls->cur_num_peers, n_peers_cls->num_peers);
342
343   if (n_peers_cls->num_peers == n_peers_cls->cur_num_peers)
344   { /* All peers are ready -- return those to the client */
345     GNUNET_assert (NULL != n_peers_cls->callback);
346
347     LOG (GNUNET_ERROR_TYPE_DEBUG,
348         "returning %" PRIX32 " peers to the client\n",
349         n_peers_cls->num_peers);
350     n_peers_cls->callback (n_peers_cls->cls, n_peers_cls->ids, n_peers_cls->num_peers);
351
352     GNUNET_free (n_peers_cls);
353   }
354 }
355
356
357 /**
358  * Reinitialise a previously initialised sampler element.
359  *
360  * @param sampler pointer to the memory that keeps the value.
361  */
362   static void
363 RPS_sampler_elem_reinit (struct RPS_SamplerElement *sampler_el)
364 {
365   sampler_el->is_empty = EMPTY;
366
367   // I guess I don't need to call GNUNET_CRYPTO_hmac_derive_key()...
368   GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_STRONG,
369                              &(sampler_el->auth_key.key),
370                              GNUNET_CRYPTO_HASH_LENGTH);
371
372   #ifdef TO_FILE
373   /* Create a file(-name) to store internals to */
374   int size;
375   char *end;
376   char *buf;
377   char name_buf[512];
378   size_t keylen = (sizeof (struct GNUNET_CRYPTO_AuthKey)) * 8;
379
380   if (keylen % 5 > 0)
381     keylen += 5 - keylen % 5;
382   keylen /= 5;
383   buf = GNUNET_malloc (keylen + 1);
384
385   end = GNUNET_STRINGS_data_to_string (&(sampler_el->auth_key.key),
386                                        sizeof (struct GNUNET_CRYPTO_AuthKey),
387                                        buf,
388                                        keylen);
389
390   if (NULL == end)
391   {
392     GNUNET_free (buf);
393     GNUNET_break (0);
394   }
395   else
396   {
397     *end = '\0';
398   }
399
400   size = GNUNET_snprintf (name_buf, sizeof (name_buf), "sampler_el-%s-", buf);
401   if (0 > size)
402     LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to create name_buf\n");
403
404   if (NULL == (sampler_el->file_name = GNUNET_DISK_mktemp (name_buf)))
405     LOG (GNUNET_ERROR_TYPE_WARNING, "Could not create file\n");
406   #endif /* TO_FILE */
407
408   sampler_el->last_client_request = GNUNET_TIME_UNIT_FOREVER_ABS;
409
410   sampler_el->birth = GNUNET_TIME_absolute_get ();
411   sampler_el->num_peers = 0;
412   sampler_el->num_change = 0;
413 }
414
415
416 /**
417  * (Re)Initialise given Sampler with random min-wise independent function.
418  *
419  * In this implementation this means choosing an auth_key for later use in
420  * a hmac at random.
421  *
422  * @return a newly created RPS_SamplerElement which currently holds no id.
423  */
424   struct RPS_SamplerElement *
425 RPS_sampler_elem_create (void)
426 {
427   struct RPS_SamplerElement *s;
428
429   s = GNUNET_new (struct RPS_SamplerElement);
430
431   RPS_sampler_elem_reinit (s);
432
433   return s;
434 }
435
436
437 /**
438  * Input an PeerID into the given sampler element.
439  *
440  * @param sampler the sampler the @a s_elem belongs to.
441  *                Needed to know the
442  */
443 static void
444 RPS_sampler_elem_next (struct RPS_SamplerElement *s_elem,
445                        struct RPS_Sampler *sampler,
446                        const struct GNUNET_PeerIdentity *other)
447 {
448   struct GNUNET_HashCode other_hash;
449
450   s_elem->num_peers++;
451
452   #ifdef TO_FILE
453   to_file (s_elem->file_name,
454            "Got id %s",
455            GNUNET_i2s_full (other));
456   #endif /* TO_FILE */
457
458   if (0 == GNUNET_CRYPTO_cmp_peer_identity (other, &(s_elem->peer_id)))
459   {
460     LOG (GNUNET_ERROR_TYPE_DEBUG, "         Got PeerID %s\n",
461         GNUNET_i2s (other));
462     LOG (GNUNET_ERROR_TYPE_DEBUG, "Have already PeerID %s\n",
463         GNUNET_i2s (&(s_elem->peer_id)));
464   }
465   else
466   {
467     GNUNET_CRYPTO_hmac(&s_elem->auth_key,
468         other,
469         sizeof(struct GNUNET_PeerIdentity),
470         &other_hash);
471
472     if (EMPTY == s_elem->is_empty)
473     {
474       LOG (GNUNET_ERROR_TYPE_DEBUG,
475            "Got PeerID %s; Simply accepting (was empty previously).\n",
476            GNUNET_i2s(other));
477       s_elem->peer_id = *other;
478       s_elem->peer_id_hash = other_hash;
479
480       s_elem->num_change++;
481     }
482     else if (0 > GNUNET_CRYPTO_hash_cmp (&other_hash, &s_elem->peer_id_hash))
483     {
484       LOG (GNUNET_ERROR_TYPE_DEBUG, "           Got PeerID %s\n",
485           GNUNET_i2s (other));
486       LOG (GNUNET_ERROR_TYPE_DEBUG, "Discarding old PeerID %s\n",
487           GNUNET_i2s (&s_elem->peer_id));
488       s_elem->peer_id = *other;
489       s_elem->peer_id_hash = other_hash;
490
491       s_elem->num_change++;
492     }
493     else
494     {
495       LOG (GNUNET_ERROR_TYPE_DEBUG, "        Got PeerID %s\n",
496           GNUNET_i2s (other));
497       LOG (GNUNET_ERROR_TYPE_DEBUG, "Keeping old PeerID %s\n",
498           GNUNET_i2s (&s_elem->peer_id));
499     }
500   }
501   s_elem->is_empty = NOT_EMPTY;
502   #ifdef TO_FILE
503   to_file (s_elem->file_name,
504            "Now holding %s",
505            GNUNET_i2s_full (&s_elem->peer_id));
506   #endif /* TO_FILE */
507 }
508
509
510 /**
511  * Get the size of the sampler.
512  *
513  * @param sampler the sampler to return the size of.
514  * @return the size of the sampler
515  */
516 unsigned int
517 RPS_sampler_get_size (struct RPS_Sampler *sampler)
518 {
519   return sampler->sampler_size;
520 }
521
522
523 /**
524  * Grow or shrink the size of the sampler.
525  *
526  * @param sampler the sampler to resize.
527  * @param new_size the new size of the sampler
528  */
529 static void
530 sampler_resize (struct RPS_Sampler *sampler, unsigned int new_size)
531 {
532   unsigned int old_size;
533   uint32_t i;
534
535   // TODO check min and max size
536
537   old_size = sampler->sampler_size;
538
539   if (old_size > new_size)
540   { /* Shrinking */
541     /* Temporary store those to properly call the removeCB on those later */
542
543     LOG (GNUNET_ERROR_TYPE_DEBUG,
544          "Shrinking sampler %d -> %d\n",
545          old_size,
546          new_size);
547     #ifdef TO_FILE
548     to_file (sampler->file_name,
549          "Shrinking sampler %d -> %d",
550          old_size,
551          new_size);
552
553     for (i = new_size ; i < old_size ; i++)
554     {
555       to_file (sampler->file_name,
556                "-%" PRIu32 ": %s",
557                i,
558                sampler->sampler_elements[i]->file_name);
559     }
560     #endif /* TO_FILE */
561     GNUNET_array_grow (sampler->sampler_elements,
562         sampler->sampler_size,
563         new_size);
564     LOG (GNUNET_ERROR_TYPE_DEBUG,
565         "sampler->sampler_elements now points to %p\n",
566         sampler->sampler_elements);
567
568   }
569   else if (old_size < new_size)
570   { /* Growing */
571     LOG (GNUNET_ERROR_TYPE_DEBUG,
572          "Growing sampler %d -> %d\n",
573          old_size,
574          new_size);
575     #ifdef TO_FILE
576     to_file (sampler->file_name,
577          "Growing sampler %d -> %d",
578          old_size,
579          new_size);
580     #endif /* TO_FILE */
581     GNUNET_array_grow (sampler->sampler_elements,
582         sampler->sampler_size,
583         new_size);
584
585     for (i = old_size ; i < new_size ; i++)
586     { /* Add new sampler elements */
587       sampler->sampler_elements[i] = RPS_sampler_elem_create ();
588       #ifdef TO_FILE
589       to_file (sampler->file_name,
590                "+%" PRIu32 ": %s",
591                i,
592                sampler->sampler_elements[i]->file_name);
593       #endif /* TO_FILE */
594     }
595   }
596   else
597   {
598     LOG (GNUNET_ERROR_TYPE_DEBUG, "Size remains the same -- nothing to do\n");
599     return;
600   }
601
602   GNUNET_assert (sampler->sampler_size == new_size);
603 }
604
605
606 /**
607  * Grow or shrink the size of the sampler.
608  *
609  * @param sampler the sampler to resize.
610  * @param new_size the new size of the sampler
611  */
612 void
613 RPS_sampler_resize (struct RPS_Sampler *sampler, unsigned int new_size)
614 {
615   GNUNET_assert (0 < new_size);
616   sampler_resize (sampler, new_size);
617 }
618
619
620 /**
621  * Empty the sampler.
622  *
623  * @param sampler the sampler to empty.
624  * @param new_size the new size of the sampler
625  */
626 static void
627 sampler_empty (struct RPS_Sampler *sampler)
628 {
629   sampler_resize (sampler, 0);
630 }
631
632
633 /**
634  * Initialise a tuple of sampler elements.
635  *
636  * @param init_size the size the sampler is initialised with
637  * @param ins_cb the callback that will be called on every PeerID that is
638  *               newly inserted into a sampler element
639  * @param ins_cls the closure given to #ins_cb
640  * @param rem_cb the callback that will be called on every PeerID that is
641  *               removed from a sampler element
642  * @param rem_cls the closure given to #rem_cb
643  * @return a handle to a sampler that consists of sampler elements.
644  */
645 struct RPS_Sampler *
646 RPS_sampler_init (size_t init_size,
647                   struct GNUNET_TIME_Relative max_round_interval)
648 {
649   struct RPS_Sampler *sampler;
650   //uint32_t i;
651
652   /* Initialise context around extended sampler */
653   min_size = 10; // TODO make input to _samplers_init()
654   max_size = 1000; // TODO make input to _samplers_init()
655
656   sampler = GNUNET_new (struct RPS_Sampler);
657
658   #ifdef TO_FILE
659   if (NULL == (sampler->file_name = GNUNET_DISK_mktemp ("sampler-")))
660     LOG (GNUNET_ERROR_TYPE_WARNING,
661          "Could not create file\n");
662   #endif /* TO_FILE */
663
664   sampler->sampler_size = 0;
665   sampler->sampler_elements = NULL;
666   sampler->max_round_interval = max_round_interval;
667   //sampler->sampler_elements = GNUNET_new_array(init_size, struct GNUNET_PeerIdentity);
668   //GNUNET_array_grow (sampler->sampler_elements, sampler->sampler_size, min_size);
669   RPS_sampler_resize (sampler, init_size);
670
671   client_get_index = 0;
672
673   //GNUNET_assert (init_size == sampler->sampler_size);
674   return sampler;
675 }
676
677
678 /**
679  * A fuction to update every sampler in the given list
680  *
681  * @param sampler the sampler to update.
682  * @param id the PeerID that is put in the sampler
683  */
684   void
685 RPS_sampler_update (struct RPS_Sampler *sampler,
686                     const struct GNUNET_PeerIdentity *id)
687 {
688   uint32_t i;
689
690   #ifdef TO_FILE
691   to_file (sampler->file_name,
692            "Got %s",
693            GNUNET_i2s_full (id));
694   #endif /* TO_FILE */
695
696   for (i = 0 ; i < sampler->sampler_size ; i++)
697   {
698     RPS_sampler_elem_next (sampler->sampler_elements[i],
699                            sampler,
700                            id);
701   }
702 }
703
704
705 /**
706  * Reinitialise all previously initialised sampler elements with the given value.
707  *
708  * Used to get rid of a PeerID.
709  *
710  * @param sampler the sampler to reinitialise a sampler element in.
711  * @param id the id of the sampler elements to update.
712  */
713   void
714 RPS_sampler_reinitialise_by_value (struct RPS_Sampler *sampler,
715                                    const struct GNUNET_PeerIdentity *id)
716 {
717   uint32_t i;
718
719   for ( i = 0 ; i < sampler->sampler_size ; i++ )
720   {
721     if ( 0 == GNUNET_CRYPTO_cmp_peer_identity(id, &(sampler->sampler_elements[i]->peer_id)) )
722     {
723       LOG (GNUNET_ERROR_TYPE_DEBUG, "Reinitialising sampler\n");
724       RPS_sampler_elem_reinit (sampler->sampler_elements[i]);
725     }
726   }
727 }
728
729
730 /**
731  * Get one random peer out of the sampled peers.
732  *
733  * We might want to reinitialise this sampler after giving the
734  * corrsponding peer to the client.
735  * Only used internally
736  */
737 static void
738 sampler_get_rand_peer2 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
739 {
740   struct GetPeerCls *gpc = cls;
741   uint32_t r_index;
742
743   gpc->get_peer_task = NULL;
744   GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, gpc);
745   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
746     return;
747
748   /**;
749    * Choose the r_index of the peer we want to return
750    * at random from the interval of the gossip list
751    */
752   r_index = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
753       gpc->sampler->sampler_size);
754
755   if ( EMPTY == gpc->sampler->sampler_elements[r_index]->is_empty )
756   {
757     gpc->get_peer_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
758                                                                    GNUNET_TIME_UNIT_SECONDS,
759                                                                    .1),
760                                                        &sampler_get_rand_peer2,
761                                                        cls);
762     return;
763   }
764
765   *gpc->id = gpc->sampler->sampler_elements[r_index]->peer_id;
766
767   gpc->cont (gpc->cont_cls, gpc->id);
768   GNUNET_free (gpc);
769 }
770
771
772 /**
773  * Get one random peer out of the sampled peers.
774  *
775  * We might want to reinitialise this sampler after giving the
776  * corrsponding peer to the client.
777  */
778 static void
779 sampler_get_rand_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
780 {
781   struct GetPeerCls *gpc = cls;
782   struct GNUNET_PeerIdentity tmp_id;
783   unsigned int empty_flag;
784   struct RPS_SamplerElement *s_elem;
785   struct GNUNET_TIME_Relative last_request_diff;
786   uint32_t tmp_client_get_index;
787
788   gpc->get_peer_task = NULL;
789   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
790     return;
791
792   LOG (GNUNET_ERROR_TYPE_DEBUG, "Single peer was requested\n");
793
794
795   /* Store the next #client_get_index to check whether we cycled over the whole list */
796   if (0 < client_get_index)
797     tmp_client_get_index = client_get_index - 1;
798   else
799     tmp_client_get_index = gpc->sampler->sampler_size - 1;
800
801   LOG (GNUNET_ERROR_TYPE_DEBUG,
802       "sched for later if index reaches %" PRIX32 " (sampler size: %" PRIX32 ").\n",
803       tmp_client_get_index, gpc->sampler->sampler_size);
804
805   do
806   { /* Get first non empty sampler */
807     if (tmp_client_get_index == client_get_index)
808     { /* We once cycled over the whole list */
809       LOG (GNUNET_ERROR_TYPE_DEBUG, "reached tmp_index %" PRIX32 ".\n",
810            client_get_index);
811       GNUNET_assert (NULL == gpc->get_peer_task);
812       gpc->get_peer_task =
813         GNUNET_SCHEDULER_add_delayed (gpc->sampler->max_round_interval,
814                                       &sampler_get_rand_peer,
815                                       cls);
816       return;
817     }
818
819     tmp_id = gpc->sampler->sampler_elements[client_get_index]->peer_id;
820     empty_flag = gpc->sampler->sampler_elements[client_get_index]->is_empty;
821     RPS_sampler_elem_reinit (gpc->sampler->sampler_elements[client_get_index]);
822     if (EMPTY != empty_flag)
823       RPS_sampler_elem_next (gpc->sampler->sampler_elements[client_get_index],
824                              gpc->sampler,
825                              &tmp_id);
826
827     /* Cycle the #client_get_index one step further */
828     if ( client_get_index == gpc->sampler->sampler_size - 1 )
829       client_get_index = 0;
830     else
831       client_get_index++;
832
833     LOG (GNUNET_ERROR_TYPE_DEBUG, "incremented index to %" PRIX32 ".\n",
834          client_get_index);
835   } while (EMPTY == gpc->sampler->sampler_elements[client_get_index]->is_empty);
836
837   s_elem = gpc->sampler->sampler_elements[client_get_index];
838   *gpc->id = s_elem->peer_id;
839
840   /* Check whether we may use this sampler to give it back to the client */
841   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != s_elem->last_client_request.abs_value_us)
842   {
843     last_request_diff =
844       GNUNET_TIME_absolute_get_difference (s_elem->last_client_request,
845                                            GNUNET_TIME_absolute_get ());
846     /* We're not going to give it back now if it was
847      * already requested by a client this round */
848     if (last_request_diff.rel_value_us < gpc->sampler->max_round_interval.rel_value_us)
849     {
850       LOG (GNUNET_ERROR_TYPE_DEBUG,
851           "Last client request on this sampler was less than max round interval ago -- scheduling for later\n");
852       ///* How many time remains untile the next round has started? */
853       //inv_last_request_diff =
854       //  GNUNET_TIME_absolute_get_difference (last_request_diff,
855       //                                       sampler->max_round_interval);
856       // add a little delay
857       /* Schedule it one round later */
858       GNUNET_assert (NULL == gpc->get_peer_task);
859       gpc->get_peer_task =
860         GNUNET_SCHEDULER_add_delayed (gpc->sampler->max_round_interval,
861                                       &sampler_get_rand_peer,
862                                       cls);
863       return;
864     }
865     // TODO add other reasons to wait here
866   }
867
868   s_elem->last_client_request = GNUNET_TIME_absolute_get ();
869
870   GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, gpc);
871   gpc->cont (gpc->cont_cls, gpc->id);
872   GNUNET_free (gpc);
873 }
874
875
876 /**
877  * Get n random peers out of the sampled peers.
878  *
879  * We might want to reinitialise this sampler after giving the
880  * corrsponding peer to the client.
881  * Random with or without consumption?
882  *
883  * @param sampler the sampler to get peers from.
884  * @param cb callback that will be called once the ids are ready.
885  * @param cls closure given to @a cb
886  * @param for_client #GNUNET_YES if result is used for client,
887  *                   #GNUNET_NO if used internally
888  * @param num_peers the number of peers requested
889  */
890   void
891 RPS_sampler_get_n_rand_peers (struct RPS_Sampler *sampler,
892                               RPS_sampler_n_rand_peers_ready_cb cb,
893                               void *cls, uint32_t num_peers, int for_client)
894 {
895   GNUNET_assert (0 != sampler->sampler_size);
896
897   // TODO check if we have too much (distinct) sampled peers
898   uint32_t i;
899   struct NRandPeersReadyCls *cb_cls;
900   struct GetPeerCls *gpc;
901
902   cb_cls = GNUNET_new (struct NRandPeersReadyCls);
903   cb_cls->num_peers = num_peers;
904   cb_cls->cur_num_peers = 0;
905   cb_cls->ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
906   cb_cls->callback = cb;
907   cb_cls->cls = cls;
908
909   #ifdef TO_FILE
910   if (GNUNET_NO == for_client)
911   {
912     to_file (sampler->file_name,
913              "This sampler is probably for Brahms itself");
914   }
915   else if (GNUNET_YES == for_client)
916   {
917     to_file (sampler->file_name,
918              "This sampler is probably for the client");
919   }
920   else
921   {
922     to_file (sampler->file_name,
923              "This shouldn't happen: for_client is %i",
924              for_client);
925   }
926   #endif /* TO_FILE */
927
928   LOG (GNUNET_ERROR_TYPE_DEBUG,
929       "Scheduling requests for %" PRIX32 " peers\n", num_peers);
930
931   for (i = 0 ; i < num_peers ; i++)
932   {
933     gpc = GNUNET_new (struct GetPeerCls);
934     gpc->sampler = sampler;
935     gpc->cont = check_n_peers_ready;
936     gpc->cont_cls = cb_cls;
937     gpc->id = &cb_cls->ids[i];
938
939     // maybe add a little delay
940     if (GNUNET_YES == for_client)
941       gpc->get_peer_task = GNUNET_SCHEDULER_add_now (&sampler_get_rand_peer, gpc);
942     else if (GNUNET_NO == for_client)
943       gpc->get_peer_task = GNUNET_SCHEDULER_add_now (&sampler_get_rand_peer2, gpc);
944     else
945       GNUNET_assert (0);
946
947     GNUNET_CONTAINER_DLL_insert (gpc_head, gpc_tail, gpc);
948   }
949 }
950
951
952 /**
953  * Counts how many Samplers currently hold a given PeerID.
954  *
955  * @param sampler the sampler to count ids in.
956  * @param id the PeerID to count.
957  *
958  * @return the number of occurrences of id.
959  */
960   uint32_t
961 RPS_sampler_count_id (struct RPS_Sampler *sampler,
962                       const struct GNUNET_PeerIdentity *id)
963 {
964   uint32_t count;
965   uint32_t i;
966
967   count = 0;
968   for ( i = 0 ; i < sampler->sampler_size ; i++ )
969   {
970     if ( 0 == GNUNET_CRYPTO_cmp_peer_identity (&sampler->sampler_elements[i]->peer_id, id)
971         && EMPTY != sampler->sampler_elements[i]->is_empty)
972       count++;
973   }
974   return count;
975 }
976
977
978 /**
979  * Cleans the sampler.
980  */
981   void
982 RPS_sampler_destroy (struct RPS_Sampler *sampler)
983 {
984   struct GetPeerCls *i;
985
986   for (i = gpc_head; NULL != i; i = gpc_head)
987   {
988     GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, i);
989     GNUNET_SCHEDULER_cancel (i->get_peer_task);
990     GNUNET_free (i);
991   }
992
993   sampler_empty (sampler);
994   GNUNET_free (sampler);
995 }
996
997 /* end of gnunet-service-rps.c */