codesonar fixes
[oweals/gnunet.git] / src / fs / perf_gnunet_service_fs_p2p.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file fs/perf_gnunet_service_fs_p2p.c
23  * @brief profile P2P routing using simple publish + download operation
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "fs_test_lib.h"
28 #include "gnunet_testing_lib.h"
29
30 #define VERBOSE GNUNET_NO
31
32 /**
33  * File-size we use for testing.
34  */
35 #define FILESIZE (1024 * 1024 * 1)
36
37 /**
38  * How long until we give up on transmitting the message?
39  */
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
41
42 #define NUM_DAEMONS 2
43
44 #define SEED 42
45
46 static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS];
47
48 static int ok;
49
50 static struct GNUNET_TIME_Absolute start_time;
51
52 static const char *progname;
53
54 static void
55 do_stop (void *cls,
56          const struct GNUNET_SCHEDULER_TaskContext *tc)
57 {
58   GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS,
59                                daemons);
60 }
61
62
63 /**
64  * Master context for 'stat_run'.
65  */
66 struct StatMaster
67 {
68   struct GNUNET_STATISTICS_Handle *stat;  
69   unsigned int daemon;
70   unsigned int value;
71 };
72
73 struct StatValues
74 {
75   const char *subsystem;
76   const char *name;
77 };
78
79 /**
80  * Statistics we print out.
81  */
82 static struct StatValues stats[] =
83   {
84     { "fs", "# queries forwarded"},
85     { "fs", "# replies received and matched"},
86     { "fs", "# results found locally"},
87     { "fs", "# requests forwarded due to high load"},
88     { "fs", "# requests done for free (low load)"},
89     { "fs", "# requests dropped, priority insufficient"},
90     { "fs", "# requests done for a price (normal load)"},
91     { "fs", "# requests dropped by datastore (queue length limit)"},
92     { "fs", "# P2P searches received"},
93     { "fs", "# P2P searches discarded (queue length bound)"},
94     { "fs", "# replies received for local clients"},
95     { "fs", "# queries retransmitted to same target"},
96     { "fs", "cummulative artificial delay introduced (ms)"},
97     { "core", "# bytes decrypted"},
98     { "core", "# bytes encrypted"},
99     { "transport", "# bytes received via TCP"},
100     { "transport", "# bytes transmitted via TCP"},
101     { "datacache", "# bytes stored"},
102     { NULL, NULL}
103   };
104
105
106 /**
107  * Callback function to process statistic values.
108  *
109  * @param cls closure
110  * @param subsystem name of subsystem that created the statistic
111  * @param name the name of the datum
112  * @param value the current value
113  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
114  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
115  */
116 static int
117 print_stat (void *cls,
118             const char *subsystem,
119             const char *name,
120             uint64_t value,
121             int is_persistent)
122 {
123   struct StatMaster *sm = cls;
124   fprintf (stderr,
125            "Peer %2u: %12s/%50s = %12llu\n",
126            sm->daemon,
127            subsystem,
128            name,
129            (unsigned long long) value);
130   return GNUNET_OK;
131 }
132
133
134 /**
135  * Function that gathers stats from all daemons.
136  */
137 static void
138 stat_run (void *cls,
139           const struct GNUNET_SCHEDULER_TaskContext *tc);
140
141
142 /**
143  * Function called when GET operation on stats is done.
144  */
145 static void
146 get_done (void *cls,
147           int success)
148 {
149   struct StatMaster *sm = cls;
150   GNUNET_break (GNUNET_OK ==  success);
151   sm->value++;
152   GNUNET_SCHEDULER_add_now (&stat_run, sm);
153 }
154
155
156 /**
157  * Function that gathers stats from all daemons.
158  */
159 static void
160 stat_run (void *cls,
161           const struct GNUNET_SCHEDULER_TaskContext *tc)
162 {
163   struct StatMaster *sm = cls;
164  
165   if (stats[sm->value].name != NULL)
166     {
167       GNUNET_STATISTICS_get (sm->stat,
168 #if 0
169                              NULL, NULL, 
170 #else
171                              stats[sm->value].subsystem,
172                              stats[sm->value].name,
173 #endif
174                              GNUNET_TIME_UNIT_FOREVER_REL,
175                              &get_done,
176                              &print_stat, sm);
177       return;
178     }
179   GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO);
180   sm->value = 0;
181   sm->daemon++;
182   if (sm->daemon == NUM_DAEMONS)
183     {
184       GNUNET_free (sm);
185       GNUNET_SCHEDULER_add_now (&do_stop, NULL);
186       return;
187     }
188   sm->stat = GNUNET_STATISTICS_create ("<driver>",
189                                        GNUNET_FS_TEST_get_configuration (daemons,
190                                                                          sm->daemon));
191   GNUNET_SCHEDULER_add_now (&stat_run, sm);
192 }
193
194
195 static void
196 do_report (void *cls,
197          const struct GNUNET_SCHEDULER_TaskContext *tc)
198 {
199   struct GNUNET_TIME_Relative del;
200   char *fancy; 
201   struct StatMaster *sm;
202   
203   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
204     {
205       del = GNUNET_TIME_absolute_get_duration (start_time);
206       if (del.rel_value == 0)
207         del.rel_value = 1;
208       fancy = GNUNET_STRINGS_byte_size_fancy (((unsigned long long)FILESIZE) * 1000LL / del.rel_value);
209       fprintf (stdout,
210                "Download speed was %s/s\n",
211                fancy);
212       GNUNET_free (fancy);
213       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214                   "Finished download, shutting down\n",
215                   (unsigned long long) FILESIZE);
216       sm = GNUNET_malloc (sizeof (struct StatMaster));
217       sm->stat = GNUNET_STATISTICS_create ("<driver>",
218                                            GNUNET_FS_TEST_get_configuration (daemons,
219                                                                              sm->daemon));
220       GNUNET_SCHEDULER_add_now (&stat_run, sm);
221     }
222   else
223     {
224       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
225                   "Timeout during download, shutting down with error\n");
226       ok = 1;
227       GNUNET_SCHEDULER_add_now (&do_stop, NULL);
228     }
229 }
230
231
232 static void
233 do_download (void *cls,
234              const struct GNUNET_FS_Uri *uri)
235 {
236   int anonymity;
237
238   if (NULL == uri)
239     {
240       GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS,
241                                    daemons);
242       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
243                   "Timeout during upload attempt, shutting down with error\n");
244       ok = 1;
245       return;
246     }
247   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
248               "Downloading %llu bytes\n",
249               (unsigned long long) FILESIZE);
250   start_time = GNUNET_TIME_absolute_get ();
251   if (NULL != strstr (progname, "dht"))
252     anonymity = 0;
253   else
254     anonymity = 1;
255   GNUNET_FS_TEST_download (daemons[0],
256                            TIMEOUT,
257                            anonymity, SEED, uri, 
258                            VERBOSE, 
259                            &do_report, NULL);
260 }
261
262
263 static void
264 do_publish (void *cls,
265             const char *emsg)
266 {
267   int do_index;
268   int anonymity;
269
270   if (NULL != emsg)
271     {
272       GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS,
273                                    daemons);
274       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
275                   "Error trying to connect: %s\n",
276                   emsg);
277       ok = 1;
278       return;
279     }
280   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281               "Publishing %llu bytes\n",
282               (unsigned long long) FILESIZE);
283   if (NULL != strstr (progname, "index"))
284     do_index = GNUNET_YES;
285   else
286     do_index = GNUNET_NO;
287   if (NULL != strstr (progname, "dht"))
288     anonymity = 0;
289   else
290     anonymity = 1;
291   
292   GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS-1],
293                           TIMEOUT,
294                           anonymity, 
295                           do_index, FILESIZE, SEED, 
296                           VERBOSE, 
297                           &do_download, NULL);
298 }
299
300
301 static void
302 do_connect (void *cls,
303             const struct GNUNET_SCHEDULER_TaskContext *tc)
304 {
305   struct GNUNET_TESTING_PeerGroup *pg;
306
307   GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE));
308   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309               "Daemons started, will now try to connect them\n");
310   pg = GNUNET_FS_TEST_get_group (daemons);
311   GNUNET_break ( (NUM_DAEMONS - 1) * 2
312                  == (GNUNET_TESTING_create_topology (pg, 
313                                                      GNUNET_TESTING_TOPOLOGY_LINE,
314                                                      GNUNET_TESTING_TOPOLOGY_NONE,
315                                                      NULL)));
316   GNUNET_TESTING_connect_topology (pg,
317                                    GNUNET_TESTING_TOPOLOGY_LINE,                                   
318                                    GNUNET_TESTING_TOPOLOGY_OPTION_NONE,
319                                    0.0,
320                                    &do_publish,
321                                    NULL);
322 }
323
324
325 static void
326 run (void *cls,
327      char *const *args,
328      const char *cfgfile,
329      const struct GNUNET_CONFIGURATION_Handle *cfg)
330 {
331   GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf",
332                                 TIMEOUT,
333                                 NUM_DAEMONS,
334                                 daemons,
335                                 &do_connect,
336                                 NULL);
337 }
338
339
340 int
341 main (int argc, char *argv[])
342 {
343   char *const argvx[] = { 
344     "perf-gnunet-service-fs-p2p",
345     "-c",
346     "fs_test_lib_data.conf",
347 #if VERBOSE
348     "-L", "DEBUG",
349 #endif
350     NULL
351   };
352   struct GNUNET_GETOPT_CommandLineOption options[] = {
353     GNUNET_GETOPT_OPTION_END
354   };
355   progname = argv[0];
356   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/");
357   GNUNET_log_setup ("perf_gnunet_service_fs_p2p_index", 
358 #if VERBOSE
359                     "DEBUG",
360 #else
361                     "WARNING",
362 #endif
363                     NULL);
364   GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1,
365                       argvx, "perf-gnunet-service-fs-p2p-index",
366                       "nohelp", options, &run, NULL);
367   GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/");
368   return ok;
369 }
370
371 /* end of perf_gnunet_service_fs_p2p_index.c */