remove 'illegal' (non-reentrant) log logic from signal handler
[oweals/gnunet.git] / src / topology / test_gnunet_daemon_topology.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012 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  * @file topology/test_gnunet_daemon_topology.c
22  * @brief testcase for topology maintenance code
23  * @author Christian Grothoff
24  * @author xrs
25  */
26 #include "platform.h"
27 #include "gnunet_testbed_service.h"
28 #include "gnunet_statistics_service.h"
29
30
31 #define NUM_PEERS 8
32
33 /*
34  * The threshold defines the number of connection that are needed
35  * for one peer to pass the test. Be aware that setting NUM_PEERS
36  * too high can cause bandwidth problems for the testing peers.
37  * Normal should be 5KB/s per peer. See gnunet-config -s ats.
38  * schanzen 12/2019: This _only_ makes sense if we connect to the
39  * actual network as in the test we do not connect to more than 1 peer.
40  * => reducing to 1 for now, was NUM_PEERS / 2
41  */
42 #define THRESHOLD 1
43
44 /**
45  * How long until we give up on connecting the peers?
46  */
47 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
48
49 /*
50  * Store manual connections.
51  */
52 static unsigned int connect_left;
53
54 /*
55  * Result of the testcase.
56  */
57 static int result;
58
59 /*
60  * Peers that reached the threshold of connections.
61  */
62 static int checked_peers;
63
64 /*
65  * Testbed operations.
66  */
67 struct GNUNET_TESTBED_Operation *op[NUM_PEERS];
68
69 /*
70  * Timeout for testcase.
71  */
72 static struct GNUNET_SCHEDULER_Task *timeout_tid;
73
74 /*
75  * Peer context for every testbed peer.
76  */
77 struct peerctx
78 {
79   int index;
80   struct GNUNET_STATISTICS_Handle *statistics;
81   int connections;
82   int reported; /* GNUNET_NO | GNUNET_YES */
83 };
84
85
86 static void
87 shutdown_task (void *cls)
88 {
89   unsigned int i;
90
91   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
92               "Shutting down testcase\n");
93
94   for (i = 0; i < NUM_PEERS; i++)
95   {
96     if (NULL != op[i])
97       GNUNET_TESTBED_operation_done (op[i]);
98   }
99
100   if (NULL != timeout_tid)
101     GNUNET_SCHEDULER_cancel (timeout_tid);
102 }
103
104
105 static void
106 timeout_task (void *cls)
107 {
108   timeout_tid = NULL;
109   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
110               "Testcase timeout\n");
111
112   result = GNUNET_SYSERR;
113   GNUNET_SCHEDULER_shutdown ();
114 }
115
116
117 /*
118  * The function is called every time the topology of connected
119  * peers to a peer changes.
120  */
121 int
122 statistics_iterator (void *cls,
123                      const char *subsystem,
124                      const char *name,
125                      uint64_t value,
126                      int is_persistent)
127 {
128   struct peerctx *p_ctx = (struct peerctx*) cls;
129
130   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
131               "Peer %d: %s = %llu\n",
132               p_ctx->index,
133               name,
134               (unsigned long long) value);
135
136   if (p_ctx->connections < value)
137     p_ctx->connections = value;
138
139   if ((THRESHOLD <= value) && (GNUNET_NO == p_ctx->reported))
140   {
141     p_ctx->reported = GNUNET_YES;
142     checked_peers++;
143     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
144                 "Peer %d successfully connected to at least %d peers once.\n",
145                 p_ctx->index,
146                 THRESHOLD);
147
148     if (checked_peers == NUM_PEERS)
149     {
150       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
151                   "Test OK: All peers have connected to %d peers once.\n",
152                   THRESHOLD);
153       result = GNUNET_YES;
154       GNUNET_SCHEDULER_shutdown ();
155     }
156   }
157
158   return GNUNET_YES;
159 }
160
161
162 static void *
163 ca_statistics (void *cls,
164                const struct GNUNET_CONFIGURATION_Handle *cfg)
165 {
166   return GNUNET_STATISTICS_create ("topology", cfg);
167 }
168
169
170 void
171 da_statistics (void *cls,
172                void *op_result)
173 {
174   struct peerctx *p_ctx = (struct peerctx *) cls;
175
176   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
177                   (p_ctx->statistics, "topology", "# peers connected",
178                   statistics_iterator, p_ctx));
179
180   GNUNET_STATISTICS_destroy (p_ctx->statistics, GNUNET_NO);
181   p_ctx->statistics = NULL;
182
183   GNUNET_free (p_ctx);
184 }
185
186
187 static void
188 service_connect_complete (void *cls,
189                           struct GNUNET_TESTBED_Operation *op,
190                           void *ca_result,
191                           const char *emsg)
192 {
193   int ret;
194   struct peerctx *p_ctx = (struct peerctx*) cls;
195
196   if (NULL == ca_result)
197     GNUNET_SCHEDULER_shutdown ();
198
199   p_ctx->statistics = ca_result;
200
201   ret = GNUNET_STATISTICS_watch (ca_result,
202                                  "topology",
203                                  "# peers connected",
204                                  statistics_iterator,
205                                  p_ctx);
206
207   if (GNUNET_NO == ret)
208     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
209                 "call to GNUNET_STATISTICS_watch() failed\n");
210 }
211
212
213 static void
214 notify_connect_complete (void *cls,
215                          struct GNUNET_TESTBED_Operation *op,
216                          const char *emsg)
217 {
218   GNUNET_TESTBED_operation_done (op);
219   if (NULL != emsg)
220   {
221     fprintf (stderr, "Failed to connect two peers: %s\n", emsg);
222     result = GNUNET_SYSERR;
223     GNUNET_SCHEDULER_shutdown ();
224     return;
225   }
226   connect_left--;
227 }
228
229
230 static void
231 do_connect (void *cls,
232             struct GNUNET_TESTBED_RunHandle *h,
233             unsigned int num_peers,
234             struct GNUNET_TESTBED_Peer **peers,
235             unsigned int links_succeeded,
236             unsigned int links_failed)
237 {
238   unsigned int i;
239   struct peerctx *p_ctx;
240
241   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
242               "Threshold is set to %d.\n",
243               THRESHOLD);
244
245   GNUNET_assert (NUM_PEERS == num_peers);
246
247   for (i = 0; i < NUM_PEERS; i++)
248   {
249     p_ctx = GNUNET_new (struct peerctx);
250     p_ctx->index = i;
251     p_ctx->connections = 0;
252     p_ctx->reported = GNUNET_NO;
253
254     if (i < NUM_PEERS - 1)
255     {
256       connect_left++;
257       GNUNET_TESTBED_overlay_connect (NULL,
258                                       &notify_connect_complete, NULL,
259                                       peers[i], peers[i + 1]);
260     }
261
262     op[i] =
263       GNUNET_TESTBED_service_connect (cls,
264                                       peers[i],
265                                       "statistics",
266                                       service_connect_complete,
267                                       p_ctx,   /* cls of completion cb */
268                                       ca_statistics,   /* connect adapter */
269                                       da_statistics,   /* disconnect adapter */
270                                       p_ctx);
271   }
272
273   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
274   timeout_tid =
275     GNUNET_SCHEDULER_add_delayed (TIMEOUT,
276                                   &timeout_task,
277                                   NULL);
278 }
279
280
281 int
282 main (int argc, char *argv[])
283 {
284   result = GNUNET_SYSERR;
285   checked_peers = 0;
286
287   (void) GNUNET_TESTBED_test_run ("test-gnunet-daemon-topology",
288                                   "test_gnunet_daemon_topology_data.conf",
289                                   NUM_PEERS,
290                                   0, NULL, NULL,
291                                   &do_connect, NULL);
292   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-topology");
293
294   return (GNUNET_OK != result) ? 1 : 0;
295 }
296
297
298 /* end of test_gnunet_daemon_topology.c */