-makefile for new test_stream_local (commented)
[oweals/gnunet.git] / src / transport / gnunet-transport-connect-running-peers.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 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  * @file transport/gnunet-transport-connect-running-peers.c
22  * @brief utility to connect running peers
23  *
24  * This utility connects to running peers with each other
25  * The peers have to be started before, for example in the debugger with
26  * breakpoints set
27  */
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_os_lib.h"
33 #include "gnunet_program_lib.h"
34 #include "gnunet_scheduler_lib.h"
35 #include "gnunet_transport_service.h"
36 #include "transport.h"
37 #include "transport-testing.h"
38
39 #define VERBOSE GNUNET_NO
40
41 #define VERBOSE_ARM GNUNET_NO
42
43 #define START_ARM GNUNET_YES
44
45 /**
46  * How long until we give up on transmitting the message?
47  */
48 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
49
50 /**
51  * How long until we give up on transmitting the message?
52  */
53 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
54
55 #define MTYPE 12345
56
57 static int ok;
58
59 static GNUNET_SCHEDULER_TaskIdentifier die_task;
60
61 static GNUNET_SCHEDULER_TaskIdentifier send_task;
62
63 struct PeerContext *p1;
64
65 struct PeerContext *p2;
66
67 static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
68
69 struct GNUNET_TRANSPORT_TransmitHandle *th;
70
71 char *cfg_file_p1;
72
73 char *cfg_file_p2;
74
75 #if VERBOSE
76 #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
77 #else
78 #define OKPP do { ok++; } while (0)
79 #endif
80
81 void
82 disconnect_from_peer (struct PeerContext *p)
83 {
84   GNUNET_assert (p != NULL);
85   if (p->th != NULL)
86     GNUNET_TRANSPORT_disconnect (p->th);
87
88   if (p->cfg != NULL)
89     GNUNET_CONFIGURATION_destroy (p->cfg);
90   GNUNET_free (p);
91   p = NULL;
92 }
93
94 static void
95 end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
96 {
97   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
98
99   if (send_task != GNUNET_SCHEDULER_NO_TASK)
100     GNUNET_SCHEDULER_cancel (send_task);
101
102   if (die_task != GNUNET_SCHEDULER_NO_TASK)
103     GNUNET_SCHEDULER_cancel (die_task);
104
105   if (th != NULL)
106     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
107   th = NULL;
108
109   if (p1 != NULL)
110     disconnect_from_peer (p1);
111   if (p2 != NULL)
112     disconnect_from_peer (p2);
113 }
114
115 static void
116 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
117 {
118   die_task = GNUNET_SCHEDULER_NO_TASK;
119
120   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
121
122   if (send_task != GNUNET_SCHEDULER_NO_TASK)
123     GNUNET_SCHEDULER_cancel (send_task);
124
125   if (cc != NULL)
126     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
127
128   if (th != NULL)
129     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
130   th = NULL;
131
132   if (p1 != NULL)
133     disconnect_from_peer (p1);
134   if (p2 != NULL)
135     disconnect_from_peer (p2);
136
137   ok = GNUNET_SYSERR;
138 }
139
140
141 static size_t
142 notify_ready (void *cls, size_t size, void *buf)
143 {
144   struct PeerContext *p = cls;
145   struct GNUNET_MessageHeader *hdr;
146
147   th = NULL;
148
149   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
150               "Transmitting message with %u bytes to peer %s\n",
151               sizeof (struct GNUNET_MessageHeader), GNUNET_i2s (&p->id));
152   GNUNET_assert (size >= 256);
153
154   if (buf != NULL)
155   {
156     hdr = buf;
157     hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
158     hdr->type = htons (MTYPE);
159   }
160
161   return sizeof (struct GNUNET_MessageHeader);
162 }
163
164 static void
165 sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
166 {
167   send_task = GNUNET_SCHEDULER_NO_TASK;
168   static char t;
169
170   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
171     return;
172
173   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174               "Press <q> to quit or <1> to send from p1 to p2, <2> to send from p2 to p1, <enter> repeat\n");
175
176 read:
177   t = getchar ();
178   if (t == '1')
179   {
180     th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0,
181                                                  TIMEOUT, &notify_ready, p1);
182     return;
183   }
184   if (t == '2')
185   {
186     th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0,
187                                                  TIMEOUT, &notify_ready, p2);
188     return;
189   }
190   if (t == 'q')
191   {
192     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Exiting %c!\n", t);
193     GNUNET_SCHEDULER_add_now (&end, NULL);
194     return;
195   }
196   goto read;
197 }
198
199 static void
200 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
201                 const struct GNUNET_MessageHeader *message,
202                 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
203 {
204   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205               "Received message of type %d from peer %s!\n",
206               ntohs (message->type), GNUNET_i2s (peer));
207
208   if ((MTYPE == ntohs (message->type)) &&
209       (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
210   {
211     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Successfully received message\n");
212
213     send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
214   }
215 }
216
217 static void
218 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
219                 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
220 {
221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n",
222               GNUNET_i2s (peer), cls);
223 }
224
225
226 static void
227 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
228 {
229   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n",
230               GNUNET_i2s (peer), cls);
231 }
232
233
234
235
236 struct PeerContext *
237 connect_to_peer (const char *cfgname, GNUNET_TRANSPORT_ReceiveCallback rec,
238                  GNUNET_TRANSPORT_NotifyConnect nc,
239                  GNUNET_TRANSPORT_NotifyDisconnect nd, void *cb_cls)
240 {
241   if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
242   {
243     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File not found: `%s' \n", cfgname);
244     return NULL;
245   }
246
247   struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
248
249   p->cfg = GNUNET_CONFIGURATION_create ();
250
251   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
252   if (GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME"))
253     GNUNET_CONFIGURATION_get_value_string (p->cfg, "PATHS", "SERVICEHOME",
254                                            &p->servicehome);
255   if (NULL != p->servicehome)
256     GNUNET_DISK_directory_remove (p->servicehome);
257   /*
258    * p->arm_proc =
259    * GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
260    * "gnunet-service-arm", "-c", cfgname,
261    * #if VERBOSE_PEERS
262    * "-L", "DEBUG",
263    * #else
264    * "-L", "ERROR",
265    * #endif
266    * NULL);
267    */
268   p->nc = nc;
269   p->nd = nd;
270   p->rec = rec;
271   if (cb_cls != NULL)
272     p->cb_cls = cb_cls;
273   else
274     p->cb_cls = p;
275
276   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service `%s'\n",
277               p->servicehome);
278   p->th =
279       GNUNET_TRANSPORT_connect (p->cfg, NULL, p, &notify_receive,
280                                 &notify_connect, &notify_disconnect);
281   GNUNET_assert (p->th != NULL);
282   return p;
283 }
284
285 static void
286 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
287 {
288   cc = NULL;
289   char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
290
291   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers connected: %s <-> %s\n", p1_c,
292               GNUNET_i2s (&p2->id));
293   GNUNET_free (p1_c);
294
295   // FIXME: THIS IS REQUIRED! SEEMS TO BE A BUG!
296
297   send_task =
298       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL);
299 }
300
301 static void
302 run (void *cls, char *const *args, const char *cfgfile,
303      const struct GNUNET_CONFIGURATION_Handle *cfg)
304 {
305   die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
306
307   p1 = connect_to_peer (cfg_file_p1, &notify_receive, &notify_connect,
308                         &notify_disconnect, NULL);
309   p2 = connect_to_peer (cfg_file_p2, &notify_receive, &notify_connect,
310                         &notify_disconnect, NULL);
311
312   if ((p1 == NULL) || (p2 == NULL))
313   {
314     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
315     if (die_task != GNUNET_SCHEDULER_NO_TASK)
316       GNUNET_SCHEDULER_cancel (die_task);
317     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
318     return;
319   }
320
321   cc = GNUNET_TRANSPORT_TESTING_connect_peers (p1, p2, &testing_connect_cb,
322                                                NULL);
323
324 }
325
326
327 static int
328 check ()
329 {
330   static char *const argv[] = { "test-transport-api",
331     "-c",
332     "test_transport_api_data.conf",
333 #if VERBOSE
334     "-L", "DEBUG",
335 #endif
336     NULL
337   };
338   static struct GNUNET_GETOPT_CommandLineOption options[] = {
339     GNUNET_GETOPT_OPTION_END
340   };
341
342 #if WRITECONFIG
343   setTransportOptions ("test_transport_api_data.conf");
344 #endif
345   send_task = GNUNET_SCHEDULER_NO_TASK;
346
347   ok = 1;
348   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
349                       "util_connect_running_peers", "nohelp", options, &run,
350                       &ok);
351
352   return ok;
353 }
354
355 int
356 main (int argc, char *argv[])
357 {
358   int ret;
359
360   GNUNET_log_setup ("gnunet-transport-connect-running-peers",
361 #if VERBOSE
362                     "DEBUG",
363 #else
364                     "WARNING",
365 #endif
366                     NULL);
367
368
369   if (argc < 3)
370   {
371     FPRINTF (stderr,
372              "usage gnunet-transport-connect-running-peers <cfg_peer1> <cfg_peer2>\n");
373     return -1;
374   }
375   else
376   {
377     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Configuration file 1: `%s' \n",
378                 argv[1]);
379     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Configuration file 2: `%s'\n",
380                 argv[2]);
381   }
382
383   if (GNUNET_DISK_file_test (argv[1]) == GNUNET_NO)
384   {
385     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File not found: `%s' \n", argv[1]);
386     return -1;
387   }
388   if (GNUNET_DISK_file_test (argv[2]) == GNUNET_NO)
389   {
390     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File not found: `%s' \n", argv[2]);
391     return -1;
392   }
393
394   GNUNET_asprintf (&cfg_file_p1, argv[1]);
395   GNUNET_asprintf (&cfg_file_p2, argv[2]);
396
397   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
398               "Trying to connect peers, press control-d to stop... \n",
399               argv[1]);
400
401   ret = check ();
402
403   GNUNET_free (cfg_file_p1);
404   GNUNET_free (cfg_file_p2);
405   return ret;
406 }
407
408 /* end of gnunet-transport-connect-running-peers.c */