- connect in clique
[oweals/gnunet.git] / src / mesh / mesh_profiler.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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  * @file mesh/mesh_profiler.c
22  *
23  * @brief Profiler for mesh experiments.
24  */
25 #include <stdio.h>
26 #include "platform.h"
27 #include "mesh_test_lib.h"
28 #include "gnunet_mesh_service.h"
29 #include "gnunet_statistics_service.h"
30
31
32 /**
33  * How namy messages to send
34  */
35 #define TOTAL_PACKETS 1000
36
37 /**
38  * How namy peers to run
39  */
40 #define TOTAL_PEERS 1000
41
42 /**
43  * How long until we give up on connecting the peers?
44  */
45 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
46
47 /**
48  * Time to wait for stuff that should be rather fast
49  */
50 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
51
52
53 struct MeshPeer
54 {
55   /**
56    * Testbed Operation (to get peer id, etc).
57    */
58   struct GNUNET_TESTBED_Operation *op;
59
60   /**
61    * Peer ID.
62    */
63   struct GNUNET_PeerIdentity id;
64
65   /**
66    * Mesh handle for the root peer
67    */
68   struct GNUNET_MESH_Handle *mesh;
69
70   /**
71    * Channel handle for the root peer
72    */
73   struct GNUNET_MESH_Channel *ch;
74
75   /**
76    * Channel handle for the dest peer
77    */
78   struct GNUNET_MESH_Channel *incoming_ch;
79
80   unsigned int dest;
81   GNUNET_SCHEDULER_TaskIdentifier ping_task;
82 };
83
84 /**
85  * Testbed peer handles.
86  */
87 struct GNUNET_TESTBED_Peer **testbed_handles;
88
89 /**
90  * Testbed Operation (to get stats).
91  */
92 struct GNUNET_TESTBED_Operation *stats_op;
93
94 /**
95  * How many events have happened
96  */
97 static int ok;
98
99 /**
100  * Number of events expected to conclude the test successfully.
101  */
102 int ok_goal;
103
104 /**
105  * Size of each test packet
106  */
107 size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
108
109 /**
110  * Operation to get peer ids.
111  */
112 struct MeshPeer peers[TOTAL_PEERS];
113
114 /**
115  * Peer ids counter.
116  */
117 unsigned int p_ids;
118
119 /**
120  * Is the setup initialized?
121  */
122 static int initialized;
123
124 /**
125  * Number of payload packes sent
126  */
127 static int data_sent;
128
129 /**
130  * Number of payload packets received
131  */
132 static int data_received;
133
134 /**
135  * Number of payload packed explicitly (app level) acknowledged
136  */
137 static int data_ack;
138
139 /**
140  * Total number of currently running peers.
141  */
142 static unsigned long long peers_running;
143
144 /**
145  * Test context (to shut down).
146  */
147 struct GNUNET_MESH_TEST_Context *test_ctx;
148
149 /**
150  * Task called to shutdown test.
151  */
152 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
153
154 /**
155  * Task called to disconnect peers, before shutdown.
156  */
157 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
158
159 /**
160  * Task to perform tests
161  */
162 static GNUNET_SCHEDULER_TaskIdentifier test_task;
163
164 /**
165  * Time we started the data transmission (after channel has been established
166  * and initilized).
167  */
168 static struct GNUNET_TIME_Absolute start_time;
169
170 /**
171  *
172  */
173 static unsigned int ka_sent;
174 static unsigned int ka_received;
175
176
177 /**
178  * Show the results of the test (banwidth acheived) and log them to GAUGER
179  */
180 static void
181 show_end_data (void)
182 {
183   static struct GNUNET_TIME_Absolute end_time;
184   static struct GNUNET_TIME_Relative total_time;
185
186   end_time = GNUNET_TIME_absolute_get();
187   total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
188   FPRINTF (stderr, "Test time %s\n",
189            GNUNET_STRINGS_relative_time_to_string (total_time,
190                                                    GNUNET_YES));
191   FPRINTF (stderr, "Test bandwidth: %f kb/s\n",
192            4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
193   FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
194            TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
195 }
196
197
198 /**
199  * Shut down peergroup, clean up.
200  *
201  * @param cls Closure (unused).
202  * @param tc Task Context.
203  */
204 static void
205 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
206 {
207   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
208   shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
209 }
210
211
212 /**
213  * Disconnect from mesh services af all peers, call shutdown.
214  *
215  * @param cls Closure (unused).
216  * @param tc Task Context.
217  */
218 static void
219 disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
220 {
221   long line = (long) cls;
222   unsigned int i;
223
224   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225               "disconnecting mesh service of peers, called from line %ld\n",
226               line);
227   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
228   for (i = 0; i < TOTAL_PEERS; i++)
229   {
230     GNUNET_TESTBED_operation_done (peers[i].op);
231     GNUNET_MESH_channel_destroy (peers[i].ch);
232     GNUNET_MESH_channel_destroy (peers[i].incoming_ch);
233   }
234   GNUNET_MESH_TEST_cleanup (test_ctx);
235   if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
236   {
237     GNUNET_SCHEDULER_cancel (shutdown_handle);
238   }
239   shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
240 }
241
242
243 /**
244  * Abort test: schedule disconnect and shutdown immediately
245  *
246  * @param line Line in the code the abort is requested from (__LINE__).
247  */
248 static void
249 abort_test (long line)
250 {
251   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
252   {
253     GNUNET_SCHEDULER_cancel (disconnect_task);
254     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
255                                                 (void *) line);
256   }
257 }
258
259
260 /**
261  * Stats callback. Finish the stats testbed operation and when all stats have
262  * been iterated, shutdown the test.
263  *
264  * @param cls closure
265  * @param op the operation that has been finished
266  * @param emsg error message in case the operation has failed; will be NULL if
267  *          operation has executed successfully.
268  */
269 static void
270 stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
271 {
272   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "... collecting statistics done.\n");
273   GNUNET_TESTBED_operation_done (stats_op);
274
275   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
276     GNUNET_SCHEDULER_cancel (disconnect_task);
277   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
278                                               (void *) __LINE__);
279
280 }
281
282
283 /**
284  * Process statistic values.
285  *
286  * @param cls closure
287  * @param peer the peer the statistic belong to
288  * @param subsystem name of subsystem that created the statistic
289  * @param name the name of the datum
290  * @param value the current value
291  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
292  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
293  */
294 static int
295 stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
296                 const char *subsystem, const char *name,
297                 uint64_t value, int is_persistent)
298 {
299   static const char *s_sent = "# keepalives sent";
300   static const char *s_recv = "# keepalives received";
301   uint32_t i;
302
303   i = GNUNET_TESTBED_get_index (peer);
304   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %u - %s [%s]: %llu\n",
305               i, subsystem, name, value);
306   if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
307     ka_sent = value;
308
309   if (0 == strncmp(s_recv, name, strlen (s_recv)) && 4 == i)
310   {
311     ka_received = value;
312     GNUNET_log (GNUNET_ERROR_TYPE_INFO, " sent: %u, received: %u\n",
313                 ka_sent, ka_received);
314     if (ka_sent < 2 || ka_sent > ka_received + 1)
315       ok--;
316   }
317
318   return GNUNET_OK;
319 }
320
321
322 /**
323  * Task check that keepalives were sent and received.
324  *
325  * @param cls Closure (NULL).
326  * @param tc Task Context.
327  */
328 static void
329 collect_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
330 {
331   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
332     return;
333
334   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
335   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start collecting statistics...\n");
336   stats_op = GNUNET_TESTBED_get_statistics (TOTAL_PEERS, testbed_handles,
337                                             NULL, NULL,
338                                             stats_iterator, stats_cont, NULL);
339 }
340
341
342 /**
343  * Transmit ready callback.
344  *
345  * @param cls Closure (message type).
346  * @param size Size of the tranmist buffer.
347  * @param buf Pointer to the beginning of the buffer.
348  *
349  * @return Number of bytes written to buf.
350  */
351 static size_t
352 tmt_rdy (void *cls, size_t size, void *buf);
353
354
355 /**
356  * Task to schedule a new data transmission.
357  *
358  * @param cls Closure (peer #).
359  * @param tc Task Context.
360  */
361 static void
362 data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
363 {
364   struct GNUNET_MESH_TransmitHandle *th;
365   struct GNUNET_MESH_Channel *channel;
366   long n = (long) cls;
367
368   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
369     return;
370
371   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
372
373   channel = peers[n].ch;
374   th = GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO,
375                                           GNUNET_TIME_UNIT_FOREVER_REL,
376                                           size_payload, &tmt_rdy, (void *) 1L);
377   if (NULL == th)
378     GNUNET_abort ();
379 }
380
381
382 /**
383  * Transmit ready callback
384  *
385  * @param cls Closure (message type).
386  * @param size Size of the buffer we have.
387  * @param buf Buffer to copy data to.
388  */
389 size_t
390 tmt_rdy (void *cls, size_t size, void *buf)
391 {
392   struct GNUNET_MessageHeader *msg = buf;
393   uint32_t *data;
394
395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tmt_rdy called, filling buffer\n");
396   if (size < size_payload || NULL == buf)
397   {
398     GNUNET_break (ok >= ok_goal - 2);
399     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400                 "size %u, buf %p, data_sent %u, data_received %u\n",
401                 size, buf, data_sent, data_received);
402     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
403
404     return 0;
405   }
406   msg->size = htons (size);
407   msg->type = htons ((long) cls);
408   data = (uint32_t *) &msg[1];
409   *data = htonl (data_sent);
410   if (GNUNET_NO == initialized)
411   {
412     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
413                 "sending initializer\n");
414   }
415   else
416   {
417     data_sent++;
418     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419               " Sent packet %d\n", data_sent);
420     if (data_sent < TOTAL_PACKETS)
421     {
422       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423               " Scheduling packet %d\n", data_sent + 1);
424       GNUNET_SCHEDULER_add_now (&data_task, NULL);
425     }
426   }
427
428   return size_payload;
429 }
430
431
432 /**
433  * Function is called whenever a message is received.
434  *
435  * @param cls closure (set from GNUNET_MESH_connect)
436  * @param channel connection to the other end
437  * @param channel_ctx place to store local state associated with the channel
438  * @param message the actual message
439  * @return GNUNET_OK to keep the connection open,
440  *         GNUNET_SYSERR to close it (signal serious error)
441  */
442 int
443 data_callback (void *cls, struct GNUNET_MESH_Channel *channel,
444                void **channel_ctx,
445                const struct GNUNET_MessageHeader *message)
446 {
447 //   long n = (long) cls;
448
449   GNUNET_MESH_receive_done (channel);
450
451
452   if (GNUNET_NO == initialized)
453   {
454     initialized = GNUNET_YES;
455     start_time = GNUNET_TIME_absolute_get ();
456     GNUNET_SCHEDULER_add_now (&data_task, NULL);
457   }
458   GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO,
459                                      GNUNET_TIME_UNIT_FOREVER_REL,
460                                      size_payload, &tmt_rdy, (void *) 1L);
461
462   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
463   {
464     GNUNET_SCHEDULER_cancel (disconnect_task);
465     disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
466                                                     &disconnect_mesh_peers,
467                                                     (void *) __LINE__);
468   }
469
470   return GNUNET_OK;
471 }
472
473
474 /**
475  * Handlers, for diverse services
476  */
477 static struct GNUNET_MESH_MessageHandler handlers[] = {
478   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
479   {NULL, 0, 0}
480 };
481
482
483 /**
484  * Method called whenever another peer has added us to a channel
485  * the other peer initiated.
486  *
487  * @param cls Closure.
488  * @param channel New handle to the channel.
489  * @param initiator Peer that started the channel.
490  * @param port Port this channel is connected to.
491  * @param options channel option flags
492  * @return Initial channel context for the channel
493  *         (can be NULL -- that's not an error).
494  */
495 static void *
496 incoming_channel (void *cls, struct GNUNET_MESH_Channel *channel,
497                  const struct GNUNET_PeerIdentity *initiator,
498                  uint32_t port, enum GNUNET_MESH_ChannelOption options)
499 {
500   long n = (long) cls;
501
502   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
503               "Incoming channel from %s to peer %ld\n",
504               GNUNET_i2s (initiator), n);
505   ok++;
506   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
507   peers[n].incoming_ch = channel;
508
509   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
510   {
511     GNUNET_SCHEDULER_cancel (disconnect_task);
512     disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
513                                                     &disconnect_mesh_peers,
514                                                     (void *) __LINE__);
515   }
516
517   return NULL;
518 }
519
520 /**
521  * Function called whenever an inbound channel is destroyed.  Should clean up
522  * any associated state.
523  *
524  * @param cls closure (set from GNUNET_MESH_connect)
525  * @param channel connection to the other end (henceforth invalid)
526  * @param channel_ctx place where local state associated
527  *                   with the channel is stored
528  */
529 static void
530 channel_cleaner (void *cls, const struct GNUNET_MESH_Channel *channel,
531                  void *channel_ctx)
532 {
533   long n = (long) cls;
534
535   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
536               "Incoming channel disconnected at peer %ld\n", n);
537   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
538
539   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
540   {
541     GNUNET_SCHEDULER_cancel (disconnect_task);
542     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
543                                                 (void *) __LINE__);
544   }
545 }
546
547
548 /**
549  * @brief Send data to destination
550  *
551  * @param cls Closure (peer).
552  * @param tc Task context.
553  */
554 static void
555 ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
556 {
557   struct MeshPeer *peer = (struct MeshPeer *) cls;
558   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending data initializer...\n");
559
560   GNUNET_MESH_notify_transmit_ready (peer->ch, GNUNET_NO,
561                                      GNUNET_TIME_UNIT_FOREVER_REL,
562                                      size_payload, &tmt_rdy, (void *) 1L);
563 }
564
565
566 static struct GNUNET_TIME_Relative
567 delay_ms_rnd (unsigned int max)
568 {
569   unsigned int rnd;
570
571   rnd = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max);
572   return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, rnd);
573 }
574
575
576 /**
577  * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE MESH SERVICES.
578  *
579  * Testcase continues when the root receives confirmation of connected peers,
580  * on callback funtion ch.
581  *
582  * @param cls Closure (unsued).
583  * @param tc Task Context.
584  */
585 static void
586 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
587 {
588   enum GNUNET_MESH_ChannelOption flags;
589   unsigned long i;
590
591   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
592     return;
593
594   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start profiler\n");
595
596   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
597     GNUNET_SCHEDULER_cancel (disconnect_task);
598   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
599                                                   &disconnect_mesh_peers,
600                                                   (void *) __LINE__);
601
602   flags = GNUNET_MESH_OPTION_DEFAULT;
603   for (i = 0; i < TOTAL_PEERS; i++)
604   {
605     peers[i].dest = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
606                                               TOTAL_PEERS);
607     peers[i].ch = GNUNET_MESH_channel_create (peers[i].mesh, NULL,
608                                               &peers[peers[i].dest].id,
609                                               1, flags);
610     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%u -> %u\n", i, peers[i].dest);
611     peers[i].ping_task = GNUNET_SCHEDULER_add_delayed (delay_ms_rnd(2000),
612                                                        &ping, &peers[i]);
613   }
614   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending data initializer...\n");
615   data_ack = 0;
616   data_received = 0;
617   data_sent = 0;
618
619 }
620
621
622 /**
623  * Callback to be called when the requested peer information is available
624  *
625  * @param cls the closure from GNUNET_TESTBED_peer_get_information()
626  * @param op the operation this callback corresponds to
627  * @param pinfo the result; will be NULL if the operation has failed
628  * @param emsg error message if the operation has failed;
629  *             NULL if the operation is successfull
630  */
631 static void
632 peer_id_cb (void *cls,
633        struct GNUNET_TESTBED_Operation *op,
634        const struct GNUNET_TESTBED_PeerInformation *pinfo,
635        const char *emsg)
636 {
637   long n = (long) cls;
638
639   if (NULL == pinfo || NULL != emsg)
640   {
641     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
642     abort_test (__LINE__);
643     return;
644   }
645   peers[n].id = *(pinfo->result.id);
646   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u  id: %s\n",
647               n, GNUNET_i2s (&peers[n].id));
648   p_ids++;
649   if (p_ids < TOTAL_PEERS)
650     return;
651   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting profiler\n");
652   test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
653                                             &do_test, NULL);
654 }
655
656 /**
657  * test main: start test when all peers are connected
658  *
659  * @param cls Closure.
660  * @param ctx Argument to give to GNUNET_MESH_TEST_cleanup on test end.
661  * @param num_peers Number of peers that are running.
662  * @param testbed_peers Array of peers.
663  * @param meshes Handle to each of the MESHs of the peers.
664  */
665 static void
666 tmain (void *cls,
667        struct GNUNET_MESH_TEST_Context *ctx,
668        unsigned int num_peers,
669        struct GNUNET_TESTBED_Peer **testbed_peers,
670        struct GNUNET_MESH_Handle **meshes)
671 {
672   unsigned long i;
673
674   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
675   ok = 0;
676   test_ctx = ctx;
677   GNUNET_assert (TOTAL_PEERS == num_peers);
678   peers_running = num_peers;
679   testbed_handles = testbed_handles;
680   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
681                                                   &disconnect_mesh_peers,
682                                                   (void *) __LINE__);
683   shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
684                                                   &shutdown_task, NULL);
685   for (i = 0; i < TOTAL_PEERS; i++)
686   {
687     peers[i].mesh = meshes[i];
688     peers[i].op =
689       GNUNET_TESTBED_peer_get_information (testbed_handles[i],
690                                            GNUNET_TESTBED_PIT_IDENTITY,
691                                            &peer_id_cb, (void *) i);
692   }
693   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
694   /* Continues from pi_cb -> do_test */
695 }
696
697
698 /**
699  * Main: start profiler.
700  */
701 int
702 main (int argc, char *argv[])
703 {
704   initialized = GNUNET_NO;
705   static uint32_t ports[2];
706   const char *config_file;
707
708   config_file = "test_mesh.conf";
709
710   p_ids = 0;
711   ports[0] = 1;
712   ports[1] = 0;
713   GNUNET_MESH_TEST_run ("mesh_profiler", config_file, TOTAL_PEERS,
714                         &tmain, NULL, /* tmain cls */
715                         &incoming_channel, &channel_cleaner,
716                         handlers, ports);
717
718   if (ok_goal > ok)
719   {
720     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
721                 "FAILED! (%d/%d)\n", ok, ok_goal);
722     return 1;
723   }
724   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
725   return 0;
726 }
727
728 /* end of test_mesh_small.c */
729