tighten formatting rules
[oweals/gnunet.git] / src / rps / rps-test_util.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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file rps/rps-test_util.c
23  * @brief Some utils faciliating the view into the internals for the sampler
24  *        needed for evaluation
25  *
26  * @author Julius Bünger
27  */
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "rps-test_util.h"
32
33 #include <inttypes.h>
34
35 #define LOG(kind, ...) GNUNET_log_from (kind, "rps-test_util", __VA_ARGS__)
36
37 #define B2B_PAT "%c%c%c%c%c%c%c%c"
38 #define B2B(byte)  \
39   (byte & 0x80 ? '1' : '0'), \
40   (byte & 0x40 ? '1' : '0'), \
41   (byte & 0x20 ? '1' : '0'), \
42   (byte & 0x10 ? '1' : '0'), \
43   (byte & 0x08 ? '1' : '0'), \
44   (byte & 0x04 ? '1' : '0'), \
45   (byte & 0x02 ? '1' : '0'), \
46   (byte & 0x01 ? '1' : '0')
47
48 #ifdef TO_FILE
49
50
51 /**
52  * @brief buffer for storing the unaligned bits for the next write
53  */
54 static char buf_unaligned;
55
56 /**
57  * @brief number of bits in unaligned buffer
58  */
59 static unsigned num_bits_buf_unaligned;
60
61 static struct GNUNET_CONTAINER_MultiHashMap *open_files;
62
63
64 /**
65  * @brief Get file handle
66  *
67  * If necessary, create file handle and store it with the other file handles.
68  *
69  * @param name Name of the file
70  *
71  * @return File handle
72  */
73 struct GNUNET_DISK_FileHandle *
74 get_file_handle (const char *name)
75 {
76   struct GNUNET_HashCode hash;
77   struct GNUNET_DISK_FileHandle *fh;
78
79   if (NULL == open_files)
80   {
81     open_files = GNUNET_CONTAINER_multihashmap_create (16,
82                                                        GNUNET_NO);
83     LOG (GNUNET_ERROR_TYPE_DEBUG,
84          "Created map of open files.\n");
85   }
86   GNUNET_CRYPTO_hash (name,
87                       strlen (name),
88                       &hash);
89   if (NULL != (fh = GNUNET_CONTAINER_multihashmap_get (open_files,
90                                                        &hash)))
91     return fh;
92   fh = GNUNET_DISK_file_open (name,
93                               GNUNET_DISK_OPEN_WRITE
94                               | GNUNET_DISK_OPEN_CREATE
95                               | GNUNET_DISK_OPEN_APPEND,
96                               GNUNET_DISK_PERM_USER_READ
97                               | GNUNET_DISK_PERM_USER_WRITE
98                               | GNUNET_DISK_PERM_GROUP_READ);
99   if (NULL == fh)
100   {
101     LOG (GNUNET_ERROR_TYPE_ERROR,
102          "Opening file `%s' failed.\n",
103          name);
104     GNUNET_assert (0);
105   }
106   GNUNET_assert (GNUNET_YES ==
107                  GNUNET_CONTAINER_multihashmap_put (open_files,
108                                                     &hash,
109                                                     fh,
110                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
111   return fh;
112 }
113
114
115 /**
116  * @brief Closes the file of the current entry
117  *
118  * Implements #GNUNET_CONTAINER_HashMapIterator
119  *
120  * @param cls unused
121  * @param key unused
122  * @param value the file handle
123  *
124  * @return #GNUNET_YES if we should continue to
125  *         iterate,
126  *         #GNUNET_NO if not.
127  */
128 int
129 close_files_iter (void *cls,
130                   const struct GNUNET_HashCode *key,
131                   void *value)
132 {
133   (void) cls;
134   (void) key;
135   struct GNUNET_DISK_FileHandle *fh = value;
136
137   if (NULL != fh)
138   {
139     GNUNET_DISK_file_close (fh);
140   }
141   return GNUNET_YES;
142 }
143
144
145 /**
146  * @brief Close all files that were opened with #get_file_handle
147  *
148  * @return Success of iterating over files
149  */
150 int
151 close_all_files ()
152 {
153   int ret;
154
155   ret = GNUNET_CONTAINER_multihashmap_iterate (open_files,
156                                                close_files_iter,
157                                                NULL);
158   GNUNET_CONTAINER_multihashmap_destroy (open_files);
159   open_files = NULL;
160   return ret;
161 }
162
163
164 void
165 to_file_raw (const char *file_name, const char *buf, size_t size_buf)
166 {
167   struct GNUNET_DISK_FileHandle *f;
168   size_t size_written;
169
170   if (NULL == (f = GNUNET_DISK_file_open (file_name,
171                                           GNUNET_DISK_OPEN_APPEND
172                                           | GNUNET_DISK_OPEN_WRITE
173                                           | GNUNET_DISK_OPEN_CREATE,
174                                           GNUNET_DISK_PERM_USER_READ
175                                           | GNUNET_DISK_PERM_USER_WRITE
176                                           | GNUNET_DISK_PERM_GROUP_READ
177                                           | GNUNET_DISK_PERM_OTHER_READ)))
178   {
179     LOG (GNUNET_ERROR_TYPE_WARNING,
180          "Not able to open file %s\n",
181          file_name);
182     return;
183   }
184
185   size_written = GNUNET_DISK_file_write (f, buf, size_buf);
186   if (size_buf != size_written)
187   {
188     LOG (GNUNET_ERROR_TYPE_WARNING,
189          "Unable to write to file! (Size: %u, size_written: %u)\n",
190          size_buf,
191          size_written);
192
193     if (GNUNET_YES != GNUNET_DISK_file_close (f))
194       LOG (GNUNET_ERROR_TYPE_WARNING,
195            "Unable to close file\n");
196
197     return;
198   }
199   LOG (GNUNET_ERROR_TYPE_WARNING,
200        "Wrote %u bytes raw.\n",
201        size_written);
202   if (GNUNET_YES != GNUNET_DISK_file_close (f))
203     LOG (GNUNET_ERROR_TYPE_WARNING,
204          "Unable to close file\n");
205 }
206
207
208 void
209 to_file_raw_unaligned (const char *file_name,
210                        const char *buf,
211                        size_t size_buf,
212                        unsigned bits_needed)
213 {
214   // TODO endianness!
215   GNUNET_assert (size_buf >= (bits_needed / 8));
216   // if (0 == num_bits_buf_unaligned)
217   // {
218   //  if (0 == (bits_needed % 8))
219   //  {
220   //    to_file_raw (file_name, buf, size_buf);
221   //    return;
222   //  }
223   //  to_file_raw (file_name, buf, size_buf - 1);
224   //  buf_unaligned = buf[size_buf - 1];
225   //  num_bits_buf_unaligned = bits_needed % 8;
226   //  return;
227   // }
228   LOG (GNUNET_ERROR_TYPE_DEBUG,
229        "Was asked to write %u bits\n", bits_needed);
230
231   char buf_write[size_buf + 1];
232   const unsigned bytes_iter = (0 != bits_needed % 8 ?
233                                (bits_needed / 8) + 1 :
234                                bits_needed / 8);
235   // TODO what if no iteration happens?
236   unsigned size_buf_write = 0;
237   LOG (GNUNET_ERROR_TYPE_DEBUG,
238        "num_bits_buf_unaligned: %u\n",
239        num_bits_buf_unaligned);
240   LOG (GNUNET_ERROR_TYPE_DEBUG,
241        "ua args: size_buf: %u, bits_needed: %u -> iter: %u\n",
242        size_buf,
243        bits_needed,
244        bytes_iter);
245   buf_write[0] = buf_unaligned;
246   /* Iterate over input bytes */
247   for (unsigned i = 0; i < bytes_iter; i++)
248   {
249     /* Number of bits needed in this iteration - 8 for all except last iter */
250     unsigned num_bits_needed_iter;
251     /* Mask for bits to actually use */
252     unsigned mask_bits_needed_iter;
253     char byte_input;
254     /* Number of bits needed to align unaligned byte */
255     unsigned num_bits_to_align;
256     /* Number of bits that are to be moved */
257     unsigned num_bits_to_move;
258     /* Mask for bytes to be moved */
259     char mask_input_to_move;
260     /* Masked bits to be moved */
261     char bits_to_move;
262     /* The amount of bits needed to fit the bits to shift to the nearest spot */
263     unsigned distance_shift_bits;
264     /* Shifted bits on the move */
265     char bits_moving;
266     /* (unaligned) byte being filled with bits */
267     char byte_to_fill;
268     /* mask for needed bits of the input byte that have not been moved */
269     char mask_input_leftover;
270     /* needed bits of the input byte that have not been moved */
271     char byte_input_leftover;
272     unsigned num_bits_leftover;
273     // unsigned num_bits_discard;
274     char byte_unaligned_new;
275
276     if ((bits_needed - (i * 8)) <= 8)
277     {
278       /* last iteration */
279       num_bits_needed_iter = bits_needed - (i * 8);
280     }
281     else
282     {
283       num_bits_needed_iter = 8;
284     }
285     LOG (GNUNET_ERROR_TYPE_DEBUG,
286          "number of bits needed in this iteration: %u\n",
287          num_bits_needed_iter);
288     mask_bits_needed_iter = ((char) 1 << num_bits_needed_iter) - 1;
289     LOG (GNUNET_ERROR_TYPE_DEBUG,
290          "mask needed bits (current iter): "B2B_PAT "\n",
291          B2B (mask_bits_needed_iter));
292     LOG (GNUNET_ERROR_TYPE_DEBUG,
293          "Unaligned byte: "B2B_PAT " (%u bits)\n",
294          B2B (buf_unaligned),
295          num_bits_buf_unaligned);
296     byte_input = buf[i];
297     LOG (GNUNET_ERROR_TYPE_DEBUG,
298          "next whole input byte: "B2B_PAT "\n",
299          B2B (byte_input));
300     byte_input &= mask_bits_needed_iter;
301     num_bits_to_align = 8 - num_bits_buf_unaligned;
302     LOG (GNUNET_ERROR_TYPE_DEBUG,
303          "input byte, needed bits: "B2B_PAT "\n",
304          B2B (byte_input));
305     LOG (GNUNET_ERROR_TYPE_DEBUG,
306          "number of bits needed to align unaligned bit: %u\n",
307          num_bits_to_align);
308     num_bits_to_move = GNUNET_MIN (num_bits_to_align, num_bits_needed_iter);
309     LOG (GNUNET_ERROR_TYPE_DEBUG,
310          "number of bits of new byte to move: %u\n",
311          num_bits_to_move);
312     mask_input_to_move = ((char) 1 << num_bits_to_move) - 1;
313     LOG (GNUNET_ERROR_TYPE_DEBUG,
314          "mask of bits of new byte to take for moving: "B2B_PAT "\n",
315          B2B (mask_input_to_move));
316     bits_to_move = byte_input & mask_input_to_move;
317     LOG (GNUNET_ERROR_TYPE_DEBUG,
318          "masked bits of new byte to take for moving: "B2B_PAT "\n",
319          B2B (bits_to_move));
320     distance_shift_bits = num_bits_buf_unaligned;
321     LOG (GNUNET_ERROR_TYPE_DEBUG,
322          "distance needed to shift bits to their correct spot: %u\n",
323          distance_shift_bits);
324     bits_moving = bits_to_move << distance_shift_bits;
325     LOG (GNUNET_ERROR_TYPE_DEBUG,
326          "shifted, masked bits of new byte being moved: "B2B_PAT "\n",
327          B2B (bits_moving));
328     byte_to_fill = buf_unaligned | bits_moving;
329     LOG (GNUNET_ERROR_TYPE_DEBUG,
330          "byte being filled: "B2B_PAT "\n",
331          B2B (byte_to_fill));
332     LOG (GNUNET_ERROR_TYPE_DEBUG,
333          "pending bytes: %u\n",
334          num_bits_buf_unaligned + num_bits_needed_iter);
335     if (num_bits_buf_unaligned + num_bits_needed_iter >= 8)
336     {
337       /* buf_unaligned was aligned by filling
338        * -> can be written to storage */
339       buf_write[i] = byte_to_fill;
340       size_buf_write++;
341
342       /* store the leftover, unaligned bits in buffer */
343       mask_input_leftover = mask_bits_needed_iter & (~mask_input_to_move);
344       LOG (GNUNET_ERROR_TYPE_DEBUG,
345            "mask of leftover bits of new byte: "B2B_PAT "\n",
346            B2B (mask_input_leftover));
347       byte_input_leftover = byte_input & mask_input_leftover;
348       LOG (GNUNET_ERROR_TYPE_DEBUG,
349            "masked, leftover bits of new byte: "B2B_PAT "\n",
350            B2B (byte_input_leftover));
351       num_bits_leftover = num_bits_needed_iter - num_bits_to_move;
352       LOG (GNUNET_ERROR_TYPE_DEBUG,
353            "number of unaligned bits left: %u\n",
354            num_bits_leftover);
355       // num_bits_discard = 8 - num_bits_needed_iter;
356       byte_unaligned_new = byte_input_leftover >> num_bits_to_move;
357       LOG (GNUNET_ERROR_TYPE_DEBUG,
358            "new unaligned byte: "B2B_PAT "\n",
359            B2B (byte_unaligned_new));
360       buf_unaligned = byte_unaligned_new;
361       num_bits_buf_unaligned = num_bits_leftover % 8;
362     }
363     else
364     {
365       /* unaligned buffer still unaligned but 'fuller' */
366       buf_unaligned = byte_to_fill;
367       num_bits_buf_unaligned = (num_bits_buf_unaligned + bits_needed) % 8;
368     }
369   }
370   to_file_raw (file_name, buf_write, size_buf_write);
371   LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
372 }
373
374
375 char *
376 auth_key_to_string (struct GNUNET_CRYPTO_AuthKey auth_key)
377 {
378   int size;
379   size_t name_buf_size;
380   char *end;
381   char *buf;
382   char *name_buf;
383   size_t keylen = (sizeof(struct GNUNET_CRYPTO_AuthKey)) * 8;
384
385   name_buf_size = 512 * sizeof(char);
386   name_buf = GNUNET_malloc (name_buf_size);
387
388   if (keylen % 5 > 0)
389     keylen += 5 - keylen % 5;
390   keylen /= 5;
391   buf = GNUNET_malloc (keylen + 1);
392
393   end = GNUNET_STRINGS_data_to_string (&(auth_key.key),
394                                        sizeof(struct GNUNET_CRYPTO_AuthKey),
395                                        buf,
396                                        keylen);
397
398   if (NULL == end)
399   {
400     GNUNET_free (buf);
401     GNUNET_break (0);
402   }
403   else
404   {
405     *end = '\0';
406   }
407
408   size = GNUNET_snprintf (name_buf, name_buf_size, "sampler_el-%s", buf);
409   if (0 > size)
410     LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to create name_buf\n");
411
412   GNUNET_free (buf);
413
414   return name_buf;
415 }
416
417
418 #endif /* TO_FILE */
419
420
421 struct GNUNET_CRYPTO_AuthKey
422 string_to_auth_key (const char *str)
423 {
424   struct GNUNET_CRYPTO_AuthKey auth_key;
425
426   if (GNUNET_OK !=
427       GNUNET_STRINGS_string_to_data (str,
428                                      strlen (str),
429                                      &auth_key.key,
430                                      sizeof(struct GNUNET_CRYPTO_AuthKey)))
431   {
432     LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to convert string to data\n");
433   }
434
435   return auth_key;
436 }
437
438
439 /**
440  * @brief Try to ensure that `/tmp/rps` exists.
441  *
442  * @return #GNUNET_YES on success
443  *         #GNUNET_SYSERR on failure
444  */
445 static int
446 ensure_folder_exist (void)
447 {
448   if (GNUNET_OK !=
449       GNUNET_DISK_directory_create ("/tmp/rps"))
450   {
451     LOG (GNUNET_ERROR_TYPE_ERROR,
452          "Could not create directory `/tmp/rps'\n");
453     return GNUNET_SYSERR;
454   }
455   return GNUNET_YES;
456 }
457
458
459 char *
460 store_prefix_file_name (const unsigned int index,
461                         const char *prefix)
462 {
463   int len_file_name;
464   int out_size;
465   char *file_name;
466   char index_str[64];
467
468   if (GNUNET_SYSERR == ensure_folder_exist ())
469     return NULL;
470   out_size = GNUNET_snprintf (index_str,
471                               64,
472                               "%u",
473                               index);
474   if ((64 < out_size) ||
475       (0 > out_size) )
476   {
477     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
478                 "Failed to write string to buffer (size: %i, out_size: %i)\n",
479                 64,
480                 out_size);
481   }
482   len_file_name = (strlen (prefix)
483                    + strlen (index_str)
484                    + 11)
485                   * sizeof(char);
486   file_name = GNUNET_malloc (len_file_name);
487   out_size = GNUNET_snprintf (file_name,
488                               len_file_name,
489                               "/tmp/rps/%s-%s",
490                               prefix,
491                               index_str);
492   if ((len_file_name < out_size) ||
493       (0 > out_size) )
494   {
495     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
496                 "Failed to write string to buffer (size: %i, out_size: %i)\n",
497                 len_file_name,
498                 out_size);
499   }
500   return file_name;
501 }
502
503
504 /**
505  * @brief Factorial
506  *
507  * @param x Number of which to compute the factorial
508  *
509  * @return Factorial of @a x
510  */
511 uint32_t
512 fac (uint32_t x)
513 {
514   if (1 >= x)
515   {
516     return x;
517   }
518   return x * fac (x - 1);
519 }
520
521
522 /**
523  * @brief Binomial coefficient (n choose k)
524  *
525  * @param n
526  * @param k
527  *
528  * @return Binomial coefficient of @a n and @a k
529  */
530 uint32_t
531 binom (uint32_t n, uint32_t k)
532 {
533   // GNUNET_assert (n >= k);
534   if (k > n)
535     return 0;
536   /* if (0 > n) return 0;  - always false */
537   /* if (0 > k) return 0;  - always false */
538   if (0 == k)
539     return 1;
540   return fac (n)
541          /
542          fac (k) * fac (n - k);
543 }
544
545
546 /* end of gnunet-service-rps.c */