aboutsummaryrefslogtreecommitdiff
path: root/src/regex/gnunet-regex-profiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/regex/gnunet-regex-profiler.c')
-rw-r--r--src/regex/gnunet-regex-profiler.c1613
1 files changed, 0 insertions, 1613 deletions
diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c
deleted file mode 100644
index bd223ae8e..000000000
--- a/src/regex/gnunet-regex-profiler.c
+++ /dev/null
@@ -1,1613 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011 - 2017 GNUnet e.V.
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 regex/gnunet-regex-profiler.c
23 * @brief Regex profiler for testing distributed regex use.
24 * @author Bartlomiej Polot
25 * @author Maximilian Szengel
26 *
27 */
28
29#include <string.h>
30
31#include "platform.h"
32#include "gnunet_applications.h"
33#include "gnunet_util_lib.h"
34#include "regex_internal_lib.h"
35#include "gnunet_arm_service.h"
36#include "gnunet_dht_service.h"
37#include "gnunet_testbed_service.h"
38
39#define FIND_TIMEOUT \
40 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
41
42/**
43 * DLL of operations
44 */
45struct DLLOperation
46{
47 /**
48 * The testbed operation handle
49 */
50 struct GNUNET_TESTBED_Operation *op;
51
52 /**
53 * Closure
54 */
55 void *cls;
56
57 /**
58 * The next pointer for DLL
59 */
60 struct DLLOperation *next;
61
62 /**
63 * The prev pointer for DLL
64 */
65 struct DLLOperation *prev;
66};
67
68
69/**
70 * Available states during profiling
71 */
72enum State
73{
74 /**
75 * Initial state
76 */
77 STATE_INIT = 0,
78
79 /**
80 * Starting slaves
81 */
82 STATE_SLAVES_STARTING,
83
84 /**
85 * Creating peers
86 */
87 STATE_PEERS_CREATING,
88
89 /**
90 * Starting peers
91 */
92 STATE_PEERS_STARTING,
93
94 /**
95 * Linking peers
96 */
97 STATE_PEERS_LINKING,
98
99 /**
100 * Matching strings against announced regexes
101 */
102 STATE_SEARCH_REGEX,
103
104 /**
105 * Destroying peers; we can do this as the controller takes care of stopping a
106 * peer if it is running
107 */
108 STATE_PEERS_DESTROYING
109};
110
111
112/**
113 * Peer handles.
114 */
115struct RegexPeer
116{
117 /**
118 * Peer id.
119 */
120 unsigned int id;
121
122 /**
123 * Peer configuration handle.
124 */
125 struct GNUNET_CONFIGURATION_Handle *cfg;
126
127 /**
128 * The actual testbed peer handle.
129 */
130 struct GNUNET_TESTBED_Peer *peer_handle;
131
132 /**
133 * Peer's search string.
134 */
135 const char *search_str;
136
137 /**
138 * Set to GNUNET_YES if the peer successfully matched the above
139 * search string. GNUNET_NO if the string could not be matched
140 * during the profiler run. GNUNET_SYSERR if the string matching
141 * timed out. Undefined if search_str is NULL
142 */
143 int search_str_matched;
144
145 /**
146 * Peer's DHT handle.
147 */
148 struct GNUNET_DHT_Handle *dht_handle;
149
150 /**
151 * Handle to a running regex search.
152 */
153 struct REGEX_INTERNAL_Search *search_handle;
154
155 /**
156 * Testbed operation handle for DHT.
157 */
158 struct GNUNET_TESTBED_Operation *op_handle;
159
160 /**
161 * Peers's statistics handle.
162 */
163 struct GNUNET_STATISTICS_Handle *stats_handle;
164
165 /**
166 * The starting time of a profiling step.
167 */
168 struct GNUNET_TIME_Absolute prof_start_time;
169
170 /**
171 * Operation timeout
172 */
173 struct GNUNET_SCHEDULER_Task *timeout;
174
175 /**
176 * Daemon start
177 */
178 struct GNUNET_TESTBED_Operation *daemon_op;
179};
180
181/**
182 * Set when shutting down to avoid making more queries.
183 */
184static int in_shutdown;
185
186/**
187 * The array of peers; we fill this as the peers are given to us by the testbed
188 */
189static struct RegexPeer *peers;
190
191/**
192 * Host registration handle
193 */
194static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
195
196/**
197 * Handle to the master controller process
198 */
199static struct GNUNET_TESTBED_ControllerProc *mc_proc;
200
201/**
202 * Handle to the master controller
203 */
204static struct GNUNET_TESTBED_Controller *mc;
205
206/**
207 * Handle to global configuration
208 */
209static struct GNUNET_CONFIGURATION_Handle *cfg;
210
211/**
212 * Abort task identifier
213 */
214static struct GNUNET_SCHEDULER_Task *abort_task;
215
216/**
217 * Host registration task identifier
218 */
219static struct GNUNET_SCHEDULER_Task *register_hosts_task;
220
221/**
222 * Global event mask for all testbed events
223 */
224static uint64_t event_mask;
225
226/**
227 * The starting time of a profiling step
228 */
229static struct GNUNET_TIME_Absolute prof_start_time;
230
231/**
232 * Duration profiling step has taken
233 */
234static struct GNUNET_TIME_Relative prof_time;
235
236/**
237 * Number of peers to be started by the profiler
238 */
239static unsigned int num_peers;
240
241/**
242 * Global testing status
243 */
244static int result;
245
246/**
247 * current state of profiling
248 */
249enum State state;
250
251/**
252 * Folder where policy files are stored.
253 */
254static char *policy_dir;
255
256/**
257 * File with hostnames where to execute the test.
258 */
259static char *hosts_file;
260
261/**
262 * File with the strings to look for.
263 */
264static char *strings_file;
265
266/**
267 * Search strings (num_peers of them).
268 */
269static char **search_strings;
270
271/**
272 * How many searches are we going to start in parallel
273 */
274static long long unsigned int init_parallel_searches;
275
276/**
277 * How many searches are running in parallel
278 */
279static unsigned int parallel_searches;
280
281/**
282 * Number of strings found in the published regexes.
283 */
284static unsigned int strings_found;
285
286/**
287 * Index of peer to start next announce/search.
288 */
289static unsigned int next_search;
290
291/**
292 * Search timeout task identifier.
293 */
294static struct GNUNET_SCHEDULER_Task *search_timeout_task;
295
296/**
297 * Search timeout in seconds.
298 */
299static struct GNUNET_TIME_Relative search_timeout_time = { 60000 };
300
301/**
302 * File to log statistics to.
303 */
304static struct GNUNET_DISK_FileHandle *data_file;
305
306/**
307 * Filename to log statistics to.
308 */
309static char *data_filename;
310
311/**
312 * Prefix used for regex announcing. We need to prefix the search
313 * strings with it, in order to find something.
314 */
315static char *regex_prefix;
316
317/**
318 * What's the maximum regex reannounce period.
319 */
320static struct GNUNET_TIME_Relative reannounce_period_max;
321
322
323/******************************************************************************/
324/****************************** DECLARATIONS ********************************/
325/******************************************************************************/
326
327/**
328 * DHT connect callback.
329 *
330 * @param cls internal peer id.
331 * @param op operation handle.
332 * @param ca_result connect adapter result.
333 * @param emsg error message.
334 */
335static void
336dht_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
337 void *ca_result, const char *emsg);
338
339/**
340 * DHT connect adapter.
341 *
342 * @param cls not used.
343 * @param cfg configuration handle.
344 *
345 * @return
346 */
347static void *
348dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg);
349
350
351/**
352 * Adapter function called to destroy a connection to
353 * the DHT service
354 *
355 * @param cls closure
356 * @param op_result service handle returned from the connect adapter
357 */
358static void
359dht_da (void *cls, void *op_result);
360
361
362/**
363 * Function called by testbed once we are connected to stats
364 * service. Get the statistics for the services of interest.
365 *
366 * @param cls the 'struct RegexPeer' for which we connected to stats
367 * @param op connect operation handle
368 * @param ca_result handle to stats service
369 * @param emsg error message on failure
370 */
371static void
372stats_connect_cb (void *cls,
373 struct GNUNET_TESTBED_Operation *op,
374 void *ca_result,
375 const char *emsg);
376
377
378/**
379 * Start announcing the next regex in the DHT.
380 *
381 * @param cls Index of the next peer in the peers array.
382 */
383static void
384announce_next_regex (void *cls);
385
386
387/******************************************************************************/
388/******************************** SHUTDOWN **********************************/
389/******************************************************************************/
390
391
392/**
393 * Shutdown nicely
394 *
395 * @param cls NULL
396 */
397static void
398do_shutdown (void *cls)
399{
400 struct RegexPeer *peer;
401 unsigned int peer_cnt;
402 unsigned int search_str_cnt;
403 char output_buffer[512];
404 size_t size;
405
406 if (NULL != abort_task)
407 {
408 GNUNET_SCHEDULER_cancel (abort_task);
409 abort_task = NULL;
410 }
411 if (NULL != register_hosts_task)
412 {
413 GNUNET_SCHEDULER_cancel (register_hosts_task);
414 register_hosts_task = NULL;
415 }
416 for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
417 {
418 peer = &peers[peer_cnt];
419
420 if ((GNUNET_YES != peer->search_str_matched) && (NULL != data_file) )
421 {
422 prof_time = GNUNET_TIME_absolute_get_duration (peer->prof_start_time);
423 size =
424 GNUNET_snprintf (output_buffer,
425 sizeof(output_buffer),
426 "%p Search string not found: %s (%d)\n"
427 "%p On peer: %u (%p)\n"
428 "%p After: %s\n",
429 peer, peer->search_str, peer->search_str_matched,
430 peer, peer->id, peer,
431 peer,
432 GNUNET_STRINGS_relative_time_to_string (prof_time,
433 GNUNET_NO));
434 if (size != GNUNET_DISK_file_write (data_file, output_buffer, size))
435 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
436 }
437
438 if (NULL != peers[peer_cnt].op_handle)
439 GNUNET_TESTBED_operation_done (peers[peer_cnt].op_handle);
440 }
441
442 if (NULL != data_file)
443 {
444 GNUNET_DISK_file_close (data_file);
445 data_file = NULL;
446 }
447 for (search_str_cnt = 0;
448 search_str_cnt < num_peers && NULL != search_strings;
449 search_str_cnt++)
450 {
451 GNUNET_free (search_strings[search_str_cnt]);
452 }
453 GNUNET_free (search_strings);
454 search_strings = NULL;
455
456 if (NULL != reg_handle)
457 {
458 GNUNET_TESTBED_cancel_registration (reg_handle);
459 reg_handle = NULL;
460 }
461 if (NULL != mc)
462 {
463 GNUNET_TESTBED_controller_disconnect (mc);
464 mc = NULL;
465 }
466 if (NULL != mc_proc)
467 {
468 GNUNET_TESTBED_controller_stop (mc_proc);
469 mc_proc = NULL;
470 }
471 if (NULL != cfg)
472 {
473 GNUNET_CONFIGURATION_destroy (cfg);
474 cfg = NULL;
475 }
476}
477
478
479/**
480 * abort task to run on test timed out
481 *
482 * @param cls NULL
483 */
484static void
485do_abort (void *cls)
486{
487 unsigned long i = (unsigned long) cls;
488
489 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
490 "Aborting from line %lu...\n", i);
491 abort_task = NULL;
492 result = GNUNET_SYSERR;
493 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
494}
495
496
497/******************************************************************************/
498/********************* STATISTICS SERVICE CONNECTIONS ***********************/
499/******************************************************************************/
500
501/**
502 * Adapter function called to establish a connection to
503 * statistics service.
504 *
505 * @param cls closure
506 * @param cfg configuration of the peer to connect to; will be available until
507 * GNUNET_TESTBED_operation_done() is called on the operation returned
508 * from GNUNET_TESTBED_service_connect()
509 * @return service handle to return in 'op_result', NULL on error
510 */
511static void *
512stats_ca (void *cls,
513 const struct GNUNET_CONFIGURATION_Handle *cfg)
514{
515 return GNUNET_STATISTICS_create ("<driver>", cfg);
516}
517
518
519/**
520 * Adapter function called to destroy a connection to
521 * statistics service.
522 *
523 * @param cls closure
524 * @param op_result service handle returned from the connect adapter
525 */
526static void
527stats_da (void *cls, void *op_result)
528{
529 struct RegexPeer *peer = cls;
530
531 GNUNET_assert (op_result == peer->stats_handle);
532
533 GNUNET_STATISTICS_destroy (peer->stats_handle, GNUNET_NO);
534 peer->stats_handle = NULL;
535}
536
537
538/**
539 * Process statistic values. Write all values to global 'data_file', if present.
540 *
541 * @param cls closure
542 * @param subsystem name of subsystem that created the statistic
543 * @param name the name of the datum
544 * @param value the current value
545 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
546 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
547 */
548static int
549stats_iterator (void *cls,
550 const char *subsystem,
551 const char *name,
552 uint64_t value, int is_persistent)
553{
554 struct RegexPeer *peer = cls;
555 char output_buffer[512];
556 size_t size;
557
558 if (NULL == data_file)
559 {
560 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
561 "%p -> %s [%s]: %llu\n",
562 peer,
563 subsystem,
564 name,
565 (unsigned long long) value);
566 return GNUNET_OK;
567 }
568 size =
569 GNUNET_snprintf (output_buffer,
570 sizeof(output_buffer),
571 "%p [%s] %llu %s\n",
572 peer,
573 subsystem,
574 (unsigned long long) value,
575 name);
576 if (size != GNUNET_DISK_file_write (data_file, output_buffer, size))
577 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
578 "Unable to write to file!\n");
579
580 return GNUNET_OK;
581}
582
583
584/**
585 * Stats callback. Finish the stats testbed operation and when all stats have
586 * been iterated, shutdown the profiler.
587 *
588 * @param cls closure
589 * @param success GNUNET_OK if statistics were
590 * successfully obtained, GNUNET_SYSERR if not.
591 */
592static void
593stats_cb (void *cls,
594 int success)
595{
596 static unsigned int peer_cnt;
597 struct RegexPeer *peer = cls;
598
599 if (GNUNET_OK != success)
600 {
601 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
602 "Getting statistics for peer %u failed!\n",
603 peer->id);
604 return;
605 }
606
607 GNUNET_assert (NULL != peer->op_handle);
608
609 GNUNET_TESTBED_operation_done (peer->op_handle);
610 peer->op_handle = NULL;
611
612 peer_cnt++;
613 peer = &peers[peer_cnt];
614
615 fprintf (stderr, "s");
616 if (peer_cnt == num_peers)
617 {
618 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
619 "\nCollecting stats finished. Shutting down.\n");
620 GNUNET_SCHEDULER_shutdown ();
621 result = GNUNET_OK;
622 }
623 else
624 {
625 peer->op_handle =
626 GNUNET_TESTBED_service_connect (NULL,
627 peer->peer_handle,
628 "statistics",
629 &stats_connect_cb,
630 peer,
631 &stats_ca,
632 &stats_da,
633 peer);
634 }
635}
636
637
638/**
639 * Function called by testbed once we are connected to stats
640 * service. Get the statistics for the services of interest.
641 *
642 * @param cls the 'struct RegexPeer' for which we connected to stats
643 * @param op connect operation handle
644 * @param ca_result handle to stats service
645 * @param emsg error message on failure
646 */
647static void
648stats_connect_cb (void *cls,
649 struct GNUNET_TESTBED_Operation *op,
650 void *ca_result,
651 const char *emsg)
652{
653 struct RegexPeer *peer = cls;
654
655 if ((NULL == ca_result) || (NULL != emsg))
656 {
657 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
658 "Failed to connect to statistics service on peer %u: %s\n",
659 peer->id, emsg);
660
661 peer->stats_handle = NULL;
662 return;
663 }
664
665 peer->stats_handle = ca_result;
666
667 if (NULL == GNUNET_STATISTICS_get (peer->stats_handle, NULL, NULL,
668 &stats_cb,
669 &stats_iterator, peer))
670 {
671 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
672 "Could not get statistics of peer %u!\n", peer->id);
673 }
674}
675
676
677/**
678 * Task to collect all statistics from all peers, will shutdown the
679 * profiler, when done.
680 *
681 * @param cls NULL
682 */
683static void
684do_collect_stats (void *cls)
685{
686 struct RegexPeer *peer = &peers[0];
687
688 GNUNET_assert (NULL != peer->peer_handle);
689
690 peer->op_handle =
691 GNUNET_TESTBED_service_connect (NULL,
692 peer->peer_handle,
693 "statistics",
694 &stats_connect_cb,
695 peer,
696 &stats_ca,
697 &stats_da,
698 peer);
699}
700
701
702/******************************************************************************/
703/************************ REGEX FIND CONNECTIONS **************************/
704/******************************************************************************/
705
706
707/**
708 * Start searching for the next string in the DHT.
709 *
710 * @param cls Index of the next peer in the peers array.
711 */
712static void
713find_string (void *cls);
714
715
716/**
717 * Method called when we've found a peer that announced a regex
718 * that matches our search string. Now get the statistics.
719 *
720 * @param cls Closure provided in REGEX_INTERNAL_search.
721 * @param id Peer providing a regex that matches the string.
722 * @param get_path Path of the get request.
723 * @param get_path_length Length of get_path.
724 * @param put_path Path of the put request.
725 * @param put_path_length Length of the put_path.
726 */
727static void
728regex_found_handler (void *cls,
729 const struct GNUNET_PeerIdentity *id,
730 const struct GNUNET_PeerIdentity *get_path,
731 unsigned int get_path_length,
732 const struct GNUNET_PeerIdentity *put_path,
733 unsigned int put_path_length)
734{
735 struct RegexPeer *peer = cls;
736 char output_buffer[512];
737 size_t size;
738
739 if (GNUNET_YES == peer->search_str_matched)
740 {
741 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
742 "String %s on peer %u already matched!\n",
743 peer->search_str, peer->id);
744 return;
745 }
746
747 strings_found++;
748 parallel_searches--;
749
750 if (NULL != peer->timeout)
751 {
752 GNUNET_SCHEDULER_cancel (peer->timeout);
753 peer->timeout = NULL;
754 if (GNUNET_NO == in_shutdown)
755 GNUNET_SCHEDULER_add_now (&announce_next_regex, NULL);
756 }
757
758 if (NULL == id)
759 {
760 // FIXME not possible right now
761 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
762 "String matching timed out for string %s on peer %u (%i/%i)\n",
763 peer->search_str, peer->id, strings_found, num_peers);
764 peer->search_str_matched = GNUNET_SYSERR;
765 }
766 else
767 {
768 prof_time = GNUNET_TIME_absolute_get_duration (peer->prof_start_time);
769
770 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
771 "String %s found on peer %u after %s (%i/%i) (%u||)\n",
772 peer->search_str, peer->id,
773 GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO),
774 strings_found, num_peers, parallel_searches);
775
776 peer->search_str_matched = GNUNET_YES;
777
778 if (NULL != data_file)
779 {
780 size =
781 GNUNET_snprintf (output_buffer,
782 sizeof(output_buffer),
783 "%p Peer: %u\n"
784 "%p Search string: %s\n"
785 "%p Search duration: %s\n\n",
786 peer, peer->id,
787 peer, peer->search_str,
788 peer,
789 GNUNET_STRINGS_relative_time_to_string (prof_time,
790 GNUNET_NO));
791
792 if (size != GNUNET_DISK_file_write (data_file, output_buffer, size))
793 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
794 }
795 }
796
797 GNUNET_TESTBED_operation_done (peer->op_handle);
798 peer->op_handle = NULL;
799
800 if (strings_found == num_peers)
801 {
802 prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
803 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
804 "All strings successfully matched in %s\n",
805 GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO));
806
807 if (NULL != search_timeout_task)
808 {
809 GNUNET_SCHEDULER_cancel (search_timeout_task);
810 search_timeout_task = NULL;
811 }
812
813 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Collecting stats.\n");
814 GNUNET_SCHEDULER_add_now (&do_collect_stats, NULL);
815 }
816}
817
818
819/**
820 * Connect by string timeout task. This will cancel the profiler after the
821 * specified timeout 'search_timeout'.
822 *
823 * @param cls NULL
824 */
825static void
826search_timed_out (void *cls)
827{
828 unsigned int i;
829
830 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
831 "Finding matches to all strings did not succeed after %s.\n",
832 GNUNET_STRINGS_relative_time_to_string (search_timeout_time,
833 GNUNET_NO));
834 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
835 "Found %i of %i strings\n", strings_found, num_peers);
836
837 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
838 "Search timed out after %s."
839 "Collecting stats and shutting down.\n",
840 GNUNET_STRINGS_relative_time_to_string (search_timeout_time,
841 GNUNET_NO));
842
843 in_shutdown = GNUNET_YES;
844 for (i = 0; i < num_peers; i++)
845 {
846 if (NULL != peers[i].op_handle)
847 {
848 GNUNET_TESTBED_operation_done (peers[i].op_handle);
849 peers[i].op_handle = NULL;
850 }
851 }
852 GNUNET_SCHEDULER_add_now (&do_collect_stats, NULL);
853}
854
855
856/**
857 * Search timed out. It might still complete in the future,
858 * but we should start another one.
859 *
860 * @param cls Index of the next peer in the peers array.
861 */
862static void
863find_timed_out (void *cls)
864{
865 struct RegexPeer *p = cls;
866
867 p->timeout = NULL;
868 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
869 "Searching for string \"%s\" on peer %d timed out.\n",
870 p->search_str,
871 p->id);
872 if (GNUNET_NO == in_shutdown)
873 GNUNET_SCHEDULER_add_now (&announce_next_regex, NULL);
874}
875
876
877/**
878 * Start searching for a string in the DHT.
879 *
880 * @param cls Index of the next peer in the peers array.
881 */
882static void
883find_string (void *cls)
884{
885 unsigned int search_peer = (unsigned int) (long) cls;
886
887 if ((search_peer >= num_peers) ||
888 (GNUNET_YES == in_shutdown))
889 return;
890
891 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
892 "Searching for string \"%s\" on peer %d (%u||)\n",
893 peers[search_peer].search_str,
894 search_peer,
895 parallel_searches);
896
897 peers[search_peer].op_handle =
898 GNUNET_TESTBED_service_connect (NULL,
899 peers[search_peer].peer_handle,
900 "dht",
901 &dht_connect_cb,
902 &peers[search_peer],
903 &dht_ca,
904 &dht_da,
905 &peers[search_peer]);
906 GNUNET_assert (NULL != peers[search_peer].op_handle);
907 peers[search_peer].timeout
908 = GNUNET_SCHEDULER_add_delayed (FIND_TIMEOUT,
909 &find_timed_out,
910 &peers[search_peer]);
911}
912
913
914/**
915 * Callback called when testbed has started the daemon we asked for.
916 *
917 * @param cls NULL
918 * @param op the operation handle
919 * @param emsg NULL on success; otherwise an error description
920 */
921static void
922daemon_started (void *cls,
923 struct GNUNET_TESTBED_Operation *op,
924 const char *emsg)
925{
926 struct RegexPeer *peer = (struct RegexPeer *) cls;
927 unsigned long search_peer;
928 unsigned int i;
929
930 GNUNET_TESTBED_operation_done (peer->daemon_op);
931 peer->daemon_op = NULL;
932 if (NULL != emsg)
933 {
934 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
935 "Failed to start/stop daemon at peer %u: %s\n", peer->id, emsg);
936 GNUNET_assert (0);
937 }
938 else
939 {
940 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
941 "Daemon %u started successfully\n", peer->id);
942 }
943
944 /* Find a peer to look for a string matching the regex announced */
945 search_peer = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
946 num_peers);
947 for (i = 0; peers[search_peer].search_str != NULL; i++)
948 {
949 search_peer = (search_peer + 1) % num_peers;
950 if (i > num_peers)
951 GNUNET_assert (0); /* we ran out of peers, must be a bug */
952 }
953 peers[search_peer].search_str = search_strings[peer->id];
954 peers[search_peer].search_str_matched = GNUNET_NO;
955 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_saturating_multiply (
956 reannounce_period_max,
957 2),
958 &find_string,
959 (void *) search_peer);
960}
961
962
963/**
964 * Task to start the daemons on each peer so that the regexes are announced
965 * into the DHT.
966 *
967 * @param cls NULL
968 * @param tc the task context
969 */
970static void
971do_announce (void *cls)
972{
973 unsigned int i;
974
975 if (GNUNET_YES == in_shutdown)
976 return;
977 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
978 "Starting announce.\n");
979 for (i = 0; i < init_parallel_searches; i++)
980 {
981 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
982 " scheduling announce %u\n",
983 i);
984 (void) GNUNET_SCHEDULER_add_now (&announce_next_regex, NULL);
985 }
986}
987
988
989/**
990 * Start announcing the next regex in the DHT.
991 *
992 * @param cls Closure (unused).
993 */
994static void
995announce_next_regex (void *cls)
996{
997 struct RegexPeer *peer;
998
999 if (GNUNET_YES == in_shutdown)
1000 return;
1001 if (next_search >= num_peers)
1002 {
1003 if (strings_found != num_peers)
1004 {
1005 struct GNUNET_TIME_Relative new_delay;
1006 if (NULL != search_timeout_task)
1007 GNUNET_SCHEDULER_cancel (search_timeout_task);
1008 new_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15);
1009 search_timeout_task = GNUNET_SCHEDULER_add_delayed (new_delay,
1010 &search_timed_out,
1011 NULL);
1012 }
1013 return;
1014 }
1015
1016 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting daemon %u\n", next_search);
1017 peer = &peers[next_search];
1018 peer->daemon_op =
1019 GNUNET_TESTBED_peer_manage_service (NULL,
1020 peer->peer_handle,
1021 "regexprofiler",
1022 &daemon_started,
1023 peer,
1024 1);
1025 next_search++;
1026 parallel_searches++;
1027}
1028
1029
1030/**
1031 * DHT connect callback. Called when we are connected to the dht service for
1032 * the peer in 'cls'. If successful we connect to the stats service of this
1033 * peer and then try to match the search string of this peer.
1034 *
1035 * @param cls internal peer id.
1036 * @param op operation handle.
1037 * @param ca_result connect adapter result.
1038 * @param emsg error message.
1039 */
1040static void
1041dht_connect_cb (void *cls,
1042 struct GNUNET_TESTBED_Operation *op,
1043 void *ca_result,
1044 const char *emsg)
1045{
1046 struct RegexPeer *peer = (struct RegexPeer *) cls;
1047
1048 if ((NULL != emsg) || (NULL == op) || (NULL == ca_result))
1049 {
1050 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DHT connect failed: %s\n", emsg);
1051 GNUNET_assert (0);
1052 }
1053
1054 GNUNET_assert (NULL != peer->dht_handle);
1055 GNUNET_assert (peer->op_handle == op);
1056 GNUNET_assert (peer->dht_handle == ca_result);
1057
1058 peer->search_str_matched = GNUNET_NO;
1059 peer->search_handle = REGEX_INTERNAL_search (peer->dht_handle,
1060 peer->search_str,
1061 &regex_found_handler, peer,
1062 NULL);
1063 peer->prof_start_time = GNUNET_TIME_absolute_get ();
1064}
1065
1066
1067/**
1068 * DHT connect adapter. Opens a connection to the dht service.
1069 *
1070 * @param cls Closure (peer).
1071 * @param cfg Configuration handle.
1072 *
1073 * @return
1074 */
1075static void *
1076dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
1077{
1078 struct RegexPeer *peer = cls;
1079
1080 peer->dht_handle = GNUNET_DHT_connect (cfg, 32);
1081
1082 return peer->dht_handle;
1083}
1084
1085
1086/**
1087 * Adapter function called to destroy a connection to the dht service.
1088 *
1089 * @param cls Closure (peer).
1090 * @param op_result Service handle returned from the connect adapter.
1091 */
1092static void
1093dht_da (void *cls, void *op_result)
1094{
1095 struct RegexPeer *peer = (struct RegexPeer *) cls;
1096
1097 GNUNET_assert (peer->dht_handle == op_result);
1098
1099 if (NULL != peer->search_handle)
1100 {
1101 REGEX_INTERNAL_search_cancel (peer->search_handle);
1102 peer->search_handle = NULL;
1103 }
1104
1105 if (NULL != peer->dht_handle)
1106 {
1107 GNUNET_DHT_disconnect (peer->dht_handle);
1108 peer->dht_handle = NULL;
1109 }
1110}
1111
1112
1113/**
1114 * Signature of a main function for a testcase.
1115 *
1116 * @param cls NULL
1117 * @param h the run handle
1118 * @param num_peers_ number of peers in 'peers'
1119 * @param testbed_peers handle to peers run in the testbed. NULL upon timeout (see
1120 * GNUNET_TESTBED_test_run()).
1121 * @param links_succeeded the number of overlay link connection attempts that
1122 * succeeded
1123 * @param links_failed the number of overlay link connection attempts that
1124 * failed
1125 */
1126static void
1127test_master (void *cls,
1128 struct GNUNET_TESTBED_RunHandle *h,
1129 unsigned int num_peers_,
1130 struct GNUNET_TESTBED_Peer **testbed_peers,
1131 unsigned int links_succeeded,
1132 unsigned int links_failed)
1133{
1134 unsigned int i;
1135
1136 GNUNET_assert (num_peers_ == num_peers);
1137
1138 prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
1139 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1140 "Testbed started in %s\n",
1141 GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO));
1142
1143 if (NULL != abort_task)
1144 {
1145 GNUNET_SCHEDULER_cancel (abort_task);
1146 abort_task = NULL;
1147 }
1148
1149 for (i = 0; i < num_peers; i++)
1150 {
1151 peers[i].peer_handle = testbed_peers[i];
1152 }
1153 if (GNUNET_NO ==
1154 GNUNET_CONFIGURATION_get_value_yesno (cfg, "DHT", "DISABLE_TRY_CONNECT"))
1155 {
1156 struct GNUNET_TIME_Relative settle_time;
1157
1158 settle_time =
1159 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1160 10 * num_peers);
1161 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1162 "Waiting for DHT for %s to settle new connections.\n\n",
1163 GNUNET_STRINGS_relative_time_to_string (settle_time,
1164 GNUNET_NO));
1165 GNUNET_SCHEDULER_add_delayed (settle_time, &do_announce, NULL);
1166 }
1167 else
1168 {
1169 GNUNET_SCHEDULER_add_now (&do_announce, NULL);
1170 }
1171 search_timeout_task =
1172 GNUNET_SCHEDULER_add_delayed (search_timeout_time, &search_timed_out, NULL);
1173}
1174
1175
1176/**
1177 * Function that will be called whenever something in the testbed changes.
1178 *
1179 * @param cls closure, NULL
1180 * @param event information on what is happening
1181 */
1182static void
1183master_controller_cb (void *cls,
1184 const struct GNUNET_TESTBED_EventInformation *event)
1185{
1186 switch (event->type)
1187 {
1188 case GNUNET_TESTBED_ET_CONNECT:
1189 printf (".");
1190 break;
1191
1192 case GNUNET_TESTBED_ET_PEER_START:
1193 printf ("#");
1194 break;
1195
1196 default:
1197 break;
1198 }
1199 fflush (stdout);
1200}
1201
1202
1203/******************************************************************************/
1204/*************************** TESTBED PEER SETUP *****************************/
1205/******************************************************************************/
1206
1207/**
1208 * Process the text buffer counting the non-empty lines and separating them
1209 * with NULL characters, for later ease of copy using (as)printf.
1210 *
1211 * @param data Memory buffer with strings.
1212 * @param data_size Size of the @a data buffer in bytes.
1213 * @param str_max Maximum number of strings to return.
1214 * @return Positive number of lines found in the buffer,
1215 * #GNUNET_SYSERR otherwise.
1216 */
1217static int
1218count_and_separate_strings (char *data,
1219 uint64_t data_size,
1220 unsigned int str_max)
1221{
1222 char *buf; // Keep track of last string to skip blank lines
1223 unsigned int offset;
1224 unsigned int str_cnt;
1225
1226 buf = data;
1227 offset = 0;
1228 str_cnt = 0;
1229 while ((offset < (data_size - 1)) && (str_cnt < str_max))
1230 {
1231 offset++;
1232 if (((data[offset] == '\n')) &&
1233 (buf != &data[offset]))
1234 {
1235 data[offset] = '\0';
1236 str_cnt++;
1237 buf = &data[offset + 1];
1238 }
1239 else if ((data[offset] == '\n') ||
1240 (data[offset] == '\0'))
1241 buf = &data[offset + 1];
1242 }
1243 return str_cnt;
1244}
1245
1246
1247/**
1248 * Allocate a string array and fill it with the prefixed strings
1249 * from a pre-processed, NULL-separated memory region.
1250 *
1251 * @param data Preprocessed memory with strings
1252 * @param data_size Size of the @a data buffer in bytes.
1253 * @param strings Address of the string array to be created.
1254 * Must be freed by caller if function end in success.
1255 * @param str_cnt String count. The @a data buffer should contain
1256 * at least this many NULL-separated strings.
1257 * @return #GNUNET_OK in ase of success, #GNUNET_SYSERR otherwise.
1258 * In case of error @a strings must not be freed.
1259 */
1260static int
1261create_string_array (char *data, uint64_t data_size,
1262 char ***strings, unsigned int str_cnt)
1263{
1264 uint64_t offset;
1265 uint64_t len;
1266 unsigned int i;
1267
1268 *strings = GNUNET_malloc (sizeof(char *) * str_cnt);
1269 offset = 0;
1270 for (i = 0; i < str_cnt; i++)
1271 {
1272 len = strlen (&data[offset]);
1273 if (offset + len >= data_size)
1274 {
1275 GNUNET_free (*strings);
1276 *strings = NULL;
1277 return GNUNET_SYSERR;
1278 }
1279 if (0 == len) // empty line
1280 {
1281 offset++;
1282 i--;
1283 continue;
1284 }
1285
1286 GNUNET_asprintf (&(*strings)[i],
1287 "%s%s",
1288 regex_prefix,
1289 &data[offset]);
1290 offset += len + 1;
1291 }
1292 return GNUNET_OK;
1293}
1294
1295
1296/**
1297 * Load search strings from given filename. One search string per line.
1298 *
1299 * @param filename filename of the file containing the search strings.
1300 * @param strings set of strings loaded from file. Caller needs to free this
1301 * if number returned is greater than zero.
1302 * @param limit upper limit on the number of strings read from the file
1303 * @return number of strings found in the file. #GNUNET_SYSERR on error.
1304 */
1305static int
1306load_search_strings (const char *filename,
1307 char ***strings,
1308 unsigned int limit)
1309{
1310 char *data;
1311 uint64_t filesize;
1312 int str_cnt;
1313
1314 /* Sanity checks */
1315 if (NULL == filename)
1316 {
1317 return GNUNET_SYSERR;
1318 }
1319 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
1320 {
1321 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1322 "Could not find search strings file %s\n", filename);
1323 return GNUNET_SYSERR;
1324 }
1325 if (GNUNET_OK !=
1326 GNUNET_DISK_file_size (filename,
1327 &filesize,
1328 GNUNET_YES,
1329 GNUNET_YES))
1330 {
1331 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1332 "Search strings file %s cannot be read.\n",
1333 filename);
1334 return GNUNET_SYSERR;
1335 }
1336 if (0 == filesize)
1337 {
1338 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1339 "Search strings file %s is empty.\n",
1340 filename);
1341 return GNUNET_SYSERR;
1342 }
1343
1344 /* Read data into memory */
1345 data = GNUNET_malloc (filesize + 1);
1346 if (filesize != GNUNET_DISK_fn_read (filename,
1347 data,
1348 filesize))
1349 {
1350 GNUNET_free (data);
1351 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1352 "Could not read search strings file %s.\n",
1353 filename);
1354 return GNUNET_SYSERR;
1355 }
1356
1357 /* Process buffer and build array */
1358 str_cnt = count_and_separate_strings (data, filesize, limit);
1359 if (GNUNET_OK != create_string_array (data, filesize, strings, str_cnt))
1360 {
1361 str_cnt = GNUNET_SYSERR;
1362 }
1363 GNUNET_free (data);
1364 return str_cnt;
1365}
1366
1367
1368/**
1369 * Main function that will be run by the scheduler.
1370 *
1371 * @param cls closure
1372 * @param args remaining command-line arguments
1373 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1374 * @param config configuration
1375 */
1376static void
1377run (void *cls,
1378 char *const *args,
1379 const char *cfgfile,
1380 const struct GNUNET_CONFIGURATION_Handle *config)
1381{
1382 unsigned int nsearchstrs;
1383 unsigned int i;
1384 struct GNUNET_TIME_Relative abort_time;
1385
1386 in_shutdown = GNUNET_NO;
1387
1388 /* Check config */
1389 if (NULL == config)
1390 {
1391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1392 _ ("No configuration file given. Exiting\n"));
1393 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1394 return;
1395 }
1396 cfg = GNUNET_CONFIGURATION_dup (config);
1397 if (GNUNET_OK !=
1398 GNUNET_CONFIGURATION_get_value_string (cfg, "REGEXPROFILER",
1399 "REGEX_PREFIX",
1400 &regex_prefix))
1401 {
1402 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1403 "regexprofiler",
1404 "regex_prefix");
1405 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1406 return;
1407 }
1408 if (GNUNET_OK !=
1409 GNUNET_CONFIGURATION_get_value_number (cfg, "REGEXPROFILER",
1410 "PARALLEL_SEARCHES",
1411 &init_parallel_searches))
1412 {
1413 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1414 "Configuration option \"PARALLEL_SEARCHES\" missing."
1415 " Using default (%d)\n", 10);
1416 init_parallel_searches = 10;
1417 }
1418 if (GNUNET_OK !=
1419 GNUNET_CONFIGURATION_get_value_time (cfg, "REGEXPROFILER",
1420 "REANNOUNCE_PERIOD_MAX",
1421 &reannounce_period_max))
1422 {
1423 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1424 "reannounce_period_max not given. Using 10 minutes.\n");
1425 reannounce_period_max =
1426 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 10);
1427 }
1428
1429 /* Check arguments */
1430 if (NULL == policy_dir)
1431 {
1432 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1433 _ (
1434 "No policy directory specified on command line. Exiting.\n"));
1435 return;
1436 }
1437 if (GNUNET_YES != GNUNET_DISK_directory_test (policy_dir, GNUNET_YES))
1438 {
1439 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1440 _ ("Specified policies directory does not exist. Exiting.\n"));
1441 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1442 return;
1443 }
1444 if (0 >= (int) (num_peers = GNUNET_DISK_directory_scan (policy_dir, NULL,
1445 NULL)))
1446 {
1447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1448 _ ("No files found in `%s'\n"),
1449 policy_dir);
1450 return;
1451 }
1452 GNUNET_CONFIGURATION_set_value_string (cfg, "REGEXPROFILER",
1453 "POLICY_DIR", policy_dir);
1454 if (GNUNET_YES != GNUNET_DISK_file_test (strings_file))
1455 {
1456 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1457 _ ("No search strings file given. Exiting.\n"));
1458 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1459 return;
1460 }
1461 nsearchstrs = load_search_strings (strings_file,
1462 &search_strings,
1463 num_peers);
1464 if (num_peers != nsearchstrs)
1465 {
1466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1467 "Error loading search strings.\n");
1468 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1469 "File (%s) does not contain enough strings (%u/%u).\n",
1470 strings_file, nsearchstrs, num_peers);
1471 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1472 return;
1473 }
1474 if ((0 == num_peers) || (NULL == search_strings))
1475 {
1476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1477 _ ("Error loading search strings. Exiting.\n"));
1478 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1479 return;
1480 }
1481 for (i = 0; i < num_peers; i++)
1482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1483 "search string: %s\n",
1484 search_strings[i]);
1485
1486 /* Check logfile */
1487 if ((NULL != data_filename) &&
1488 (NULL == (data_file =
1489 GNUNET_DISK_file_open (data_filename,
1490 GNUNET_DISK_OPEN_READWRITE
1491 | GNUNET_DISK_OPEN_TRUNCATE
1492 | GNUNET_DISK_OPEN_CREATE,
1493 GNUNET_DISK_PERM_USER_READ
1494 | GNUNET_DISK_PERM_USER_WRITE))))
1495 {
1496 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1497 "open",
1498 data_filename);
1499 return;
1500 }
1501
1502 /* Initialize peers */
1503 peers = GNUNET_malloc (sizeof(struct RegexPeer) * num_peers);
1504 for (i = 0; i < num_peers; i++)
1505 peers[i].id = i;
1506
1507 GNUNET_CONFIGURATION_set_value_number (cfg,
1508 "TESTBED", "OVERLAY_RANDOM_LINKS",
1509 num_peers * 20);
1510 GNUNET_CONFIGURATION_set_value_number (cfg,
1511 "DHT", "FORCE_NSE",
1512 (long long unsigned)
1513 (log (num_peers) / log (2.0)));
1514 event_mask = 0LL;
1515/* For feedback about the start process activate these and pass master_cb */
1516 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
1517// event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
1518 event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
1519// event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT);
1520 prof_start_time = GNUNET_TIME_absolute_get ();
1521 GNUNET_TESTBED_run (hosts_file,
1522 cfg,
1523 num_peers,
1524 event_mask,
1525 &master_controller_cb,
1526 NULL, /* master_controller_cb cls */
1527 &test_master,
1528 NULL); /* test_master cls */
1529 if (GNUNET_OK !=
1530 GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
1531 "SETUP_TIMEOUT",
1532 &abort_time))
1533 {
1534 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1535 "SETUP_TIMEOUT not given. Using 15 minutes.\n");
1536 abort_time =
1537 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15);
1538 }
1539 abort_time = GNUNET_TIME_relative_add (abort_time, GNUNET_TIME_UNIT_MINUTES);
1540 abort_task =
1541 GNUNET_SCHEDULER_add_delayed (abort_time,
1542 &do_abort,
1543 (void *) __LINE__);
1544 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1545 "setup_timeout: %s\n",
1546 GNUNET_STRINGS_relative_time_to_string (abort_time, GNUNET_YES));
1547}
1548
1549
1550/**
1551 * Main function.
1552 *
1553 * @param argc argument count
1554 * @param argv argument values
1555 * @return 0 on success
1556 */
1557int
1558main (int argc, char *const *argv)
1559{
1560 struct GNUNET_GETOPT_CommandLineOption options[] = {
1561 GNUNET_GETOPT_option_filename ('o',
1562 "output-file",
1563 "FILENAME",
1564 gettext_noop (
1565 "name of the file for writing statistics"),
1566 &data_filename),
1567
1568 GNUNET_GETOPT_option_relative_time ('t',
1569 "matching-timeout",
1570 "TIMEOUT",
1571 gettext_noop (
1572 "wait TIMEOUT before ending the experiment"),
1573 &search_timeout_time),
1574
1575 GNUNET_GETOPT_option_filename ('p',
1576 "policy-dir",
1577 "DIRECTORY",
1578 gettext_noop ("directory with policy files"),
1579 &policy_dir),
1580
1581
1582 GNUNET_GETOPT_option_filename ('s',
1583 "strings-file",
1584 "FILENAME",
1585 gettext_noop (
1586 "name of file with input strings"),
1587 &strings_file),
1588
1589 GNUNET_GETOPT_option_filename ('H',
1590 "hosts-file",
1591 "FILENAME",
1592 gettext_noop (
1593 "name of file with hosts' names"),
1594 &hosts_file),
1595
1596 GNUNET_GETOPT_OPTION_END
1597 };
1598 int ret;
1599
1600 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1601 return 2;
1602 result = GNUNET_SYSERR;
1603 ret =
1604 GNUNET_PROGRAM_run (argc, argv,
1605 "gnunet-regex-profiler",
1606 _ ("Profiler for regex"),
1607 options, &run, NULL);
1608 if (GNUNET_OK != ret)
1609 return ret;
1610 if (GNUNET_OK != result)
1611 return 1;
1612 return 0;
1613}