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