uncrustify as demanded.
[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 /**
66  * @brief Get file handle
67  *
68  * If necessary, create file handle and store it with the other file handles.
69  *
70  * @param name Name of the file
71  *
72  * @return File handle
73  */
74 struct GNUNET_DISK_FileHandle *
75 get_file_handle(const char *name)
76 {
77   struct GNUNET_HashCode hash;
78   struct GNUNET_DISK_FileHandle *fh;
79
80   if (NULL == open_files)
81     {
82       open_files = GNUNET_CONTAINER_multihashmap_create(16,
83                                                         GNUNET_NO);
84       LOG(GNUNET_ERROR_TYPE_DEBUG,
85           "Created map of open files.\n");
86     }
87   GNUNET_CRYPTO_hash(name,
88                      strlen(name),
89                      &hash);
90   if (NULL != (fh = GNUNET_CONTAINER_multihashmap_get(open_files,
91                                                       &hash)))
92     return fh;
93   fh = GNUNET_DISK_file_open(name,
94                              GNUNET_DISK_OPEN_WRITE |
95                              GNUNET_DISK_OPEN_CREATE |
96                              GNUNET_DISK_OPEN_APPEND,
97                              GNUNET_DISK_PERM_USER_READ |
98                              GNUNET_DISK_PERM_USER_WRITE |
99                              GNUNET_DISK_PERM_GROUP_READ);
100   if (NULL == fh)
101     {
102       LOG(GNUNET_ERROR_TYPE_ERROR,
103           "Opening file `%s' failed.\n",
104           name);
105       GNUNET_assert(0);
106     }
107   GNUNET_assert(GNUNET_YES ==
108                 GNUNET_CONTAINER_multihashmap_put(open_files,
109                                                   &hash,
110                                                   fh,
111                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
112   return fh;
113 }
114
115
116 /**
117  * @brief Closes the file of the current entry
118  *
119  * Implements #GNUNET_CONTAINER_HashMapIterator
120  *
121  * @param cls unused
122  * @param key unused
123  * @param value the file handle
124  *
125  * @return #GNUNET_YES if we should continue to
126  *         iterate,
127  *         #GNUNET_NO if not.
128  */
129 int
130 close_files_iter(void *cls,
131                  const struct GNUNET_HashCode *key,
132                  void *value)
133 {
134   (void)cls;
135   (void)key;
136   struct GNUNET_DISK_FileHandle *fh = value;
137
138   if (NULL != fh)
139     {
140       GNUNET_DISK_file_close(fh);
141     }
142   return GNUNET_YES;
143 }
144
145
146 /**
147  * @brief Close all files that were opened with #get_file_handle
148  *
149  * @return Success of iterating over files
150  */
151 int
152 close_all_files()
153 {
154   int ret;
155
156   ret = GNUNET_CONTAINER_multihashmap_iterate(open_files,
157                                               close_files_iter,
158                                               NULL);
159   GNUNET_CONTAINER_multihashmap_destroy(open_files);
160   open_files = NULL;
161   return ret;
162 }
163
164
165
166 void
167 to_file_raw(const char *file_name, const char *buf, size_t size_buf)
168 {
169   struct GNUNET_DISK_FileHandle *f;
170   size_t size_written;
171
172   if (NULL == (f = GNUNET_DISK_file_open(file_name,
173                                          GNUNET_DISK_OPEN_APPEND |
174                                          GNUNET_DISK_OPEN_WRITE |
175                                          GNUNET_DISK_OPEN_CREATE,
176                                          GNUNET_DISK_PERM_USER_READ |
177                                          GNUNET_DISK_PERM_USER_WRITE |
178                                          GNUNET_DISK_PERM_GROUP_READ |
179                                          GNUNET_DISK_PERM_OTHER_READ)))
180     {
181       LOG(GNUNET_ERROR_TYPE_WARNING,
182           "Not able to open file %s\n",
183           file_name);
184       return;
185     }
186
187   size_written = GNUNET_DISK_file_write(f, buf, size_buf);
188   if (size_buf != size_written)
189     {
190       LOG(GNUNET_ERROR_TYPE_WARNING,
191           "Unable to write to file! (Size: %u, size_written: %u)\n",
192           size_buf,
193           size_written);
194
195       if (GNUNET_YES != GNUNET_DISK_file_close(f))
196         LOG(GNUNET_ERROR_TYPE_WARNING,
197             "Unable to close file\n");
198
199       return;
200     }
201   LOG(GNUNET_ERROR_TYPE_WARNING,
202       "Wrote %u bytes raw.\n",
203       size_written);
204   if (GNUNET_YES != GNUNET_DISK_file_close(f))
205     LOG(GNUNET_ERROR_TYPE_WARNING,
206         "Unable to close file\n");
207 }
208
209 void
210 to_file_raw_unaligned(const char *file_name,
211                       const char *buf,
212                       size_t size_buf,
213                       unsigned bits_needed)
214 {
215   // TODO endianness!
216   GNUNET_assert(size_buf >= (bits_needed / 8));
217   //if (0 == num_bits_buf_unaligned)
218   //{
219   //  if (0 == (bits_needed % 8))
220   //  {
221   //    to_file_raw (file_name, buf, size_buf);
222   //    return;
223   //  }
224   //  to_file_raw (file_name, buf, size_buf - 1);
225   //  buf_unaligned = buf[size_buf - 1];
226   //  num_bits_buf_unaligned = bits_needed % 8;
227   //  return;
228   //}
229   LOG(GNUNET_ERROR_TYPE_DEBUG,
230       "Was asked to write %u bits\n", bits_needed);
231
232   char buf_write[size_buf + 1];
233   const unsigned bytes_iter = (0 != bits_needed % 8 ?
234                                (bits_needed / 8) + 1 :
235                                bits_needed / 8);
236   // TODO what if no iteration happens?
237   unsigned size_buf_write = 0;
238   LOG(GNUNET_ERROR_TYPE_DEBUG,
239       "num_bits_buf_unaligned: %u\n",
240       num_bits_buf_unaligned);
241   LOG(GNUNET_ERROR_TYPE_DEBUG,
242       "ua args: size_buf: %u, bits_needed: %u -> iter: %u\n",
243       size_buf,
244       bits_needed,
245       bytes_iter);
246   buf_write[0] = buf_unaligned;
247   /* Iterate over input bytes */
248   for (unsigned i = 0; i < bytes_iter; i++)
249     {
250       /* Number of bits needed in this iteration - 8 for all except last iter */
251       unsigned num_bits_needed_iter;
252       /* Mask for bits to actually use */
253       unsigned mask_bits_needed_iter;
254       char byte_input;
255       /* Number of bits needed to align unaligned byte */
256       unsigned num_bits_to_align;
257       /* Number of bits that are to be moved */
258       unsigned num_bits_to_move;
259       /* Mask for bytes to be moved */
260       char mask_input_to_move;
261       /* Masked bits to be moved */
262       char bits_to_move;
263       /* The amount of bits needed to fit the bits to shift to the nearest spot */
264       unsigned distance_shift_bits;
265       /* Shifted bits on the move */
266       char bits_moving;
267       /* (unaligned) byte being filled with bits */
268       char byte_to_fill;
269       /* mask for needed bits of the input byte that have not been moved */
270       char mask_input_leftover;
271       /* needed bits of the input byte that have not been moved */
272       char byte_input_leftover;
273       unsigned num_bits_leftover;
274       //unsigned num_bits_discard;
275       char byte_unaligned_new;
276
277       if ((bits_needed - (i * 8)) <= 8)
278         {
279           /* last iteration */
280           num_bits_needed_iter = bits_needed - (i * 8);
281         }
282       else
283         {
284           num_bits_needed_iter = 8;
285         }
286       LOG(GNUNET_ERROR_TYPE_DEBUG,
287           "number of bits needed in this iteration: %u\n",
288           num_bits_needed_iter);
289       mask_bits_needed_iter = ((char)1 << num_bits_needed_iter) - 1;
290       LOG(GNUNET_ERROR_TYPE_DEBUG,
291           "mask needed bits (current iter): "B2B_PAT "\n",
292           B2B(mask_bits_needed_iter));
293       LOG(GNUNET_ERROR_TYPE_DEBUG,
294           "Unaligned byte: "B2B_PAT " (%u bits)\n",
295           B2B(buf_unaligned),
296           num_bits_buf_unaligned);
297       byte_input = buf[i];
298       LOG(GNUNET_ERROR_TYPE_DEBUG,
299           "next whole input byte: "B2B_PAT "\n",
300           B2B(byte_input));
301       byte_input &= mask_bits_needed_iter;
302       num_bits_to_align = 8 - num_bits_buf_unaligned;
303       LOG(GNUNET_ERROR_TYPE_DEBUG,
304           "input byte, needed bits: "B2B_PAT "\n",
305           B2B(byte_input));
306       LOG(GNUNET_ERROR_TYPE_DEBUG,
307           "number of bits needed to align unaligned bit: %u\n",
308           num_bits_to_align);
309       num_bits_to_move = GNUNET_MIN(num_bits_to_align, num_bits_needed_iter);
310       LOG(GNUNET_ERROR_TYPE_DEBUG,
311           "number of bits of new byte to move: %u\n",
312           num_bits_to_move);
313       mask_input_to_move = ((char)1 << num_bits_to_move) - 1;
314       LOG(GNUNET_ERROR_TYPE_DEBUG,
315           "mask of bits of new byte to take for moving: "B2B_PAT "\n",
316           B2B(mask_input_to_move));
317       bits_to_move = byte_input & mask_input_to_move;
318       LOG(GNUNET_ERROR_TYPE_DEBUG,
319           "masked bits of new byte to take for moving: "B2B_PAT "\n",
320           B2B(bits_to_move));
321       distance_shift_bits = num_bits_buf_unaligned;
322       LOG(GNUNET_ERROR_TYPE_DEBUG,
323           "distance needed to shift bits to their correct spot: %u\n",
324           distance_shift_bits);
325       bits_moving = bits_to_move << distance_shift_bits;
326       LOG(GNUNET_ERROR_TYPE_DEBUG,
327           "shifted, masked bits of new byte being moved: "B2B_PAT "\n",
328           B2B(bits_moving));
329       byte_to_fill = buf_unaligned | bits_moving;
330       LOG(GNUNET_ERROR_TYPE_DEBUG,
331           "byte being filled: "B2B_PAT "\n",
332           B2B(byte_to_fill));
333       LOG(GNUNET_ERROR_TYPE_DEBUG,
334           "pending bytes: %u\n",
335           num_bits_buf_unaligned + num_bits_needed_iter);
336       if (num_bits_buf_unaligned + num_bits_needed_iter >= 8)
337         {
338           /* buf_unaligned was aligned by filling
339            * -> can be written to storage */
340           buf_write[i] = byte_to_fill;
341           size_buf_write++;
342
343           /* store the leftover, unaligned bits in buffer */
344           mask_input_leftover = mask_bits_needed_iter & (~mask_input_to_move);
345           LOG(GNUNET_ERROR_TYPE_DEBUG,
346               "mask of leftover bits of new byte: "B2B_PAT "\n",
347               B2B(mask_input_leftover));
348           byte_input_leftover = byte_input & mask_input_leftover;
349           LOG(GNUNET_ERROR_TYPE_DEBUG,
350               "masked, leftover bits of new byte: "B2B_PAT "\n",
351               B2B(byte_input_leftover));
352           num_bits_leftover = num_bits_needed_iter - num_bits_to_move;
353           LOG(GNUNET_ERROR_TYPE_DEBUG,
354               "number of unaligned bits left: %u\n",
355               num_bits_leftover);
356           //num_bits_discard = 8 - num_bits_needed_iter;
357           byte_unaligned_new = byte_input_leftover >> num_bits_to_move;
358           LOG(GNUNET_ERROR_TYPE_DEBUG,
359               "new unaligned byte: "B2B_PAT "\n",
360               B2B(byte_unaligned_new));
361           buf_unaligned = byte_unaligned_new;
362           num_bits_buf_unaligned = num_bits_leftover % 8;
363         }
364       else
365         {
366           /* unaligned buffer still unaligned but 'fuller' */
367           buf_unaligned = byte_to_fill;
368           num_bits_buf_unaligned = (num_bits_buf_unaligned + bits_needed) % 8;
369         }
370     }
371   to_file_raw(file_name, buf_write, size_buf_write);
372   LOG(GNUNET_ERROR_TYPE_DEBUG, "\n");
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 #endif /* TO_FILE */
418
419
420 struct GNUNET_CRYPTO_AuthKey
421 string_to_auth_key(const char *str)
422 {
423   struct GNUNET_CRYPTO_AuthKey auth_key;
424
425   if (GNUNET_OK !=
426       GNUNET_STRINGS_string_to_data(str,
427                                     strlen(str),
428                                     &auth_key.key,
429                                     sizeof(struct GNUNET_CRYPTO_AuthKey)))
430     {
431       LOG(GNUNET_ERROR_TYPE_WARNING, "Failed to convert string to data\n");
432     }
433
434   return auth_key;
435 }
436
437
438 /**
439  * @brief Try to ensure that `/tmp/rps` exists.
440  *
441  * @return #GNUNET_YES on success
442  *         #GNUNET_SYSERR on failure
443  */
444 static int
445 ensure_folder_exist(void)
446 {
447   if (GNUNET_OK !=
448       GNUNET_DISK_directory_create("/tmp/rps"))
449     {
450       LOG(GNUNET_ERROR_TYPE_ERROR,
451           "Could not create directory `/tmp/rps'\n");
452       return GNUNET_SYSERR;
453     }
454   return GNUNET_YES;
455 }
456
457
458 char *
459 store_prefix_file_name(const unsigned int index,
460                        const char *prefix)
461 {
462   int len_file_name;
463   int out_size;
464   char *file_name;
465   char index_str[64];
466
467   if (GNUNET_SYSERR == ensure_folder_exist())
468     return NULL;
469   out_size = GNUNET_snprintf(index_str,
470                              64,
471                              "%u",
472                              index);
473   if (64 < out_size ||
474       0 > out_size)
475     {
476       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
477                  "Failed to write string to buffer (size: %i, out_size: %i)\n",
478                  64,
479                  out_size);
480     }
481   len_file_name = (strlen(prefix) +
482                    strlen(index_str) +
483                    11)
484                   * sizeof(char);
485   file_name = GNUNET_malloc(len_file_name);
486   out_size = GNUNET_snprintf(file_name,
487                              len_file_name,
488                              "/tmp/rps/%s-%s",
489                              prefix,
490                              index_str);
491   if (len_file_name < out_size ||
492       0 > out_size)
493     {
494       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
495                  "Failed to write string to buffer (size: %i, out_size: %i)\n",
496                  len_file_name,
497                  out_size);
498     }
499   return file_name;
500 }
501
502
503 /**
504  * @brief Factorial
505  *
506  * @param x Number of which to compute the factorial
507  *
508  * @return Factorial of @a x
509  */
510 uint32_t fac(uint32_t x)
511 {
512   if (1 >= x)
513     {
514       return x;
515     }
516   return x * fac(x - 1);
517 }
518
519 /**
520  * @brief Binomial coefficient (n choose k)
521  *
522  * @param n
523  * @param k
524  *
525  * @return Binomial coefficient of @a n and @a k
526  */
527 uint32_t binom(uint32_t n, uint32_t k)
528 {
529   //GNUNET_assert (n >= k);
530   if (k > n)
531     return 0;
532   /* if (0 > n) return 0;  - always false */
533   /* if (0 > k) return 0;  - always false */
534   if (0 == k)
535     return 1;
536   return fac(n)
537          /
538          fac(k) * fac(n - k);
539 }
540
541
542 /* end of gnunet-service-rps.c */