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