fix leaks, code cleanup
[oweals/gnunet.git] / src / testing / test_testing_topology_clique.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 2, 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 testing/test_testing_group.c
22  * @brief testcase for functions to connect two peers in testing.c
23  */
24 #include "platform.h"
25 #include "gnunet_testing_lib.h"
26 #include "gnunet_core_service.h"
27
28 #define VERBOSE GNUNET_NO
29
30 /**
31  * How long until we give up on connecting the peers?
32  */
33 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
34
35 #define DEFAULT_NUM_PEERS 4;
36
37 static int ok;
38
39 static unsigned long long num_peers;
40
41 static unsigned int total_connections;
42
43 static unsigned int expected_connections;
44
45 static int peers_left;
46
47 static struct GNUNET_TESTING_PeerGroup *pg;
48
49 static struct GNUNET_SCHEDULER_Handle *sched;
50
51 const struct GNUNET_CONFIGURATION_Handle *main_cfg;
52
53 GNUNET_SCHEDULER_TaskIdentifier die_task;
54
55 static struct GNUNET_CORE_Handle *peer1handle;
56
57 static struct GNUNET_CORE_Handle *peer2handle;
58
59 #define MTYPE 12345
60
61 static void
62 finish_testing ()
63 {
64   GNUNET_assert (pg != NULL);
65
66   if (peer1handle != NULL)
67     GNUNET_CORE_disconnect(peer1handle);
68   if (peer2handle != NULL)
69     GNUNET_CORE_disconnect(peer2handle);
70
71   GNUNET_TESTING_daemons_stop (pg);
72   ok = 0;
73 }
74
75 static int
76 process_mtype (void *cls,
77                const struct GNUNET_PeerIdentity *peer,
78                const struct GNUNET_MessageHeader *message,
79                struct GNUNET_TIME_Relative latency,
80                uint32_t distance)
81 {
82 #if VERBOSE
83   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
84               "Receiving message from `%4s'.\n", GNUNET_i2s (peer));
85 #endif
86   GNUNET_SCHEDULER_cancel (sched, die_task);
87   GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
88   return GNUNET_OK;
89 }
90
91
92 static void
93 connect_notify (void *cls,
94                 const struct GNUNET_PeerIdentity *peer,
95                 struct GNUNET_TIME_Relative latency,
96                 uint32_t distance)
97 {
98 #if VERBOSE
99   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
100               "Encrypted connection established to peer `%4s' with latency %llu\n",
101               GNUNET_i2s (peer), latency.value);
102 #endif
103 }
104
105
106 static void
107 disconnect_notify (void *cls,
108                    const struct GNUNET_PeerIdentity *peer)
109 {
110 #if VERBOSE
111   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
112               "Encrypted connection to `%4s' cut\n", GNUNET_i2s (peer));
113 #endif
114 }
115
116
117 static int
118 inbound_notify (void *cls,
119                 const struct GNUNET_PeerIdentity *other,
120                 const struct GNUNET_MessageHeader *message,
121                 struct GNUNET_TIME_Relative latency,
122                 uint32_t distance)
123 {
124 #if VERBOSE
125   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
126               "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other));
127 #endif
128   return GNUNET_OK;
129 }
130
131
132 static int
133 outbound_notify (void *cls,
134                  const struct GNUNET_PeerIdentity *other,
135                  const struct GNUNET_MessageHeader *message,
136                  struct GNUNET_TIME_Relative latency,
137                  uint32_t distance)
138 {
139 #if VERBOSE
140   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
141               "Core notifies about outbound data for `%4s'.\n",
142               GNUNET_i2s (other));
143 #endif
144   return GNUNET_OK;
145 }
146
147 static void
148 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
149 {
150 #if VERBOSE
151   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
152               "End badly was called... stopping daemons.\n");
153 #endif
154
155   if (peer1handle != NULL)
156     {
157       GNUNET_CORE_disconnect(peer1handle);
158       peer1handle = NULL;
159     }
160   if (peer2handle != NULL)
161     {
162       GNUNET_CORE_disconnect(peer2handle);
163       peer2handle = NULL;
164     }
165
166   if (pg != NULL)
167     {
168       GNUNET_TESTING_daemons_stop (pg);
169       ok = 7331;                /* Opposite of leet */
170     }
171   else
172     ok = 401;                   /* Never got peers started */
173 }
174
175 static size_t
176 transmit_ready (void *cls, size_t size, void *buf)
177 {
178   struct GNUNET_MessageHeader *m;
179
180   GNUNET_assert (buf != NULL);
181   m = (struct GNUNET_MessageHeader *) buf;
182   m->type = htons (MTYPE);
183   m->size = htons (sizeof (struct GNUNET_MessageHeader));
184   GNUNET_SCHEDULER_cancel(sched, die_task);
185   die_task =
186     GNUNET_SCHEDULER_add_delayed (sched,
187         TIMEOUT, &end_badly, "from transmit ready");
188
189   return sizeof (struct GNUNET_MessageHeader);
190 }
191
192
193 static struct GNUNET_CORE_MessageHandler handlers[] = {
194   {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)},
195   {NULL, 0, 0}
196 };
197
198
199 static void
200 init_notify (void *cls,
201              struct GNUNET_CORE_Handle *server,
202              const struct GNUNET_PeerIdentity *my_identity,
203              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
204 {
205   struct GNUNET_TESTING_Daemon *connected_peer = cls;
206   struct GNUNET_TESTING_Daemon *peer1;
207   struct GNUNET_TESTING_Daemon *peer2;
208
209   peer1 = GNUNET_TESTING_daemon_get(pg, 0);
210   peer2 = GNUNET_TESTING_daemon_get(pg, 1);
211 #if VERBOSE
212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213               "Core connection to `%4s' established, setting up handles\n",
214               GNUNET_i2s (my_identity));
215 #endif
216
217   if (connected_peer == peer1)
218     {
219       peer1handle = server;
220 #if VERBOSE
221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting core to peer 2\n");
222 #endif
223       /* connect p2 */
224       GNUNET_CORE_connect (sched,
225                            peer2->cfg,
226                            TIMEOUT,
227                            peer2,
228                            &init_notify,
229                            NULL,
230                            &connect_notify,
231                            &disconnect_notify,
232                            &inbound_notify,
233                            GNUNET_YES,
234                            &outbound_notify, GNUNET_YES, handlers);
235     }
236   else
237     {
238       GNUNET_assert(connected_peer == peer2);
239       peer2handle = server;
240 #if VERBOSE
241       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242                   "Asking core (1) for transmission to peer `%4s'\n",
243                   GNUNET_i2s (&peer2->id));
244 #endif
245
246       if (NULL == GNUNET_CORE_notify_transmit_ready (peer1->server,
247                                                      0,
248                                                      TIMEOUT,
249                                                      &peer2->id,
250                                                      sizeof (struct GNUNET_MessageHeader),
251                                                      &transmit_ready, &peer1))
252         {
253           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254                       "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
255                       GNUNET_i2s (&peer2->id));
256         }
257
258     }
259 }
260
261
262 static void
263 send_test_messages ()
264 {
265   struct GNUNET_TESTING_Daemon *peer1;
266   struct GNUNET_TESTING_Daemon *peer2;
267
268   peer1 = GNUNET_TESTING_daemon_get(pg, 0);
269   peer2 = GNUNET_TESTING_daemon_get(pg, 1);
270
271   die_task = GNUNET_SCHEDULER_add_delayed (sched,
272                                            TIMEOUT,
273                                            &end_badly, "from send test messages");
274
275   /* Send a message from peer 1 to peer 2 */
276   GNUNET_CORE_connect (sched,
277                        peer1->cfg,
278                        TIMEOUT,
279                        peer1,
280                        &init_notify,
281                        NULL,
282                        &connect_notify,
283                        &disconnect_notify,
284                        &inbound_notify,
285                        GNUNET_YES, &outbound_notify, GNUNET_YES, handlers);
286 }
287
288 void
289 topology_callback (void *cls,
290                    const struct GNUNET_PeerIdentity *first,
291                    const struct GNUNET_PeerIdentity *second,
292                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
293                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
294                    struct GNUNET_TESTING_Daemon *first_daemon,
295                    struct GNUNET_TESTING_Daemon *second_daemon,
296                    const char *emsg)
297 {
298   /* Keep track of connections here if the client needs to know?
299    * Still, we have no real handle to say the i'th peer of the peer group
300    * even though we know that X peers exist in i...  But we may want to
301    * know about the peer for logging purposes here (I'm sure we will actually
302    * so the API may need changed).  Question, should the API expose what
303    * a peer group is, or provide convenience/accessor functions?
304    *
305    * For now, I've added accessor functions, which seems like a software
306    * engineering kind of solution, but who knows/cares. */
307   if (emsg == NULL)
308     {
309       total_connections++;
310 #if VERBOSE
311       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n",
312                first_daemon->shortname,
313                second_daemon->shortname);
314 #endif
315     }
316 #if VERBOSE
317   else
318     {
319
320       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error %s\n",
321                first_daemon->shortname,
322                second_daemon->shortname, emsg);
323     }
324 #endif
325
326   if (total_connections == expected_connections)
327     {
328 #if VERBOSE
329       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
330                   "Created %d total connections, which is our target number!  Ending test.\n",
331                   total_connections);
332 #endif
333
334       GNUNET_SCHEDULER_cancel (sched, die_task);
335       die_task = GNUNET_SCHEDULER_add_now (sched, &send_test_messages, NULL);
336     }
337   else
338     {
339 #if VERBOSE
340       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341                   "Have %d total connections, Need %d\n",
342                   total_connections, expected_connections);
343 #endif
344     }
345 }
346
347
348 static void
349 create_topology ()
350 {
351   expected_connections = -1;
352   if ((pg != NULL) && (peers_left == 0))
353     {
354       /* create_topology will read the topology information from
355          the config already contained in the peer group, so should
356          we have create_topology called from start peers?  I think
357          maybe this way is best so that the client can know both
358          when peers are started, and when they are connected.
359        */
360       expected_connections = GNUNET_TESTING_create_topology (pg);
361 #if VERBOSE
362       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363                   "Have %d expected connections\n", expected_connections);
364 #endif
365     }
366
367   GNUNET_SCHEDULER_cancel (sched, die_task);
368   die_task = GNUNET_SCHEDULER_add_delayed (sched,
369                                            TIMEOUT,
370                                            &end_badly, NULL);
371 }
372
373
374 static void
375 my_cb (void *cls,
376        const struct GNUNET_PeerIdentity *id,
377        const struct GNUNET_CONFIGURATION_Handle *cfg,
378        struct GNUNET_TESTING_Daemon *d, const char *emsg)
379 {
380   GNUNET_assert (id != NULL);
381 #if VERBOSE
382   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %d out of %d\n",
383               (num_peers - peers_left) + 1, num_peers);
384 #endif
385   peers_left--;
386   if (peers_left == 0)
387     {
388 #if VERBOSE
389       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390                   "All %d daemons started, now creating topology!\n",
391                   num_peers);
392 #endif
393       GNUNET_SCHEDULER_cancel (sched, die_task);
394       /* Set up task in case topology creation doesn't finish
395        * within a reasonable amount of time */
396       die_task = GNUNET_SCHEDULER_add_delayed (sched,
397                                                GNUNET_TIME_relative_multiply
398                                                (GNUNET_TIME_UNIT_MINUTES, 5),
399                                                &end_badly, NULL);
400       create_topology ();
401       ok = 0;
402     }
403 }
404
405
406 static void
407 run (void *cls,
408      struct GNUNET_SCHEDULER_Handle *s,
409      char *const *args,
410      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
411 {
412   sched = s;
413   ok = 1;
414 #if VERBOSE
415   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
416               "Starting daemons based on config file %s\n", cfgfile);
417 #endif
418   if (GNUNET_SYSERR ==
419       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
420                                              &num_peers))
421     num_peers = DEFAULT_NUM_PEERS;
422
423   main_cfg = cfg;
424
425   peers_left = num_peers;
426
427   /* Set up a task to end testing if peer start fails */
428   die_task = GNUNET_SCHEDULER_add_delayed (sched,
429                                            GNUNET_TIME_relative_multiply
430                                            (GNUNET_TIME_UNIT_MINUTES, 5),
431                                            &end_badly, NULL);
432
433   pg = GNUNET_TESTING_daemons_start (sched, cfg,
434                                      peers_left, &my_cb, NULL,
435                                      &topology_callback, NULL, NULL);
436
437   /*
438      if (ret != GNUNET_SYSERR)
439      ret = send_test_messages (pg);
440    */
441
442 }
443
444 static int
445 check ()
446 {
447   char *const argv[] = { "test-testing-topology-clique",
448     "-c",
449     "test_testing_data_topology_clique.conf",
450 #if VERBOSE
451     "-L", "DEBUG",
452 #endif
453     NULL
454   };
455   struct GNUNET_GETOPT_CommandLineOption options[] = {
456     GNUNET_GETOPT_OPTION_END
457   };
458   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
459                       argv, "test-testing-topology-clique", "nohelp",
460                       options, &run, &ok);
461   return ok;
462 }
463
464 int
465 main (int argc, char *argv[])
466 {
467   int ret;
468
469   GNUNET_log_setup ("test-testing-topology_clique",
470 #if VERBOSE
471                     "DEBUG",
472 #else
473                     "WARNING",
474 #endif
475                     NULL);
476   ret = check ();
477   sleep (1);
478   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing");
479   return ret;
480 }
481
482 /* end of test_testing_group.c */