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