can now send a message
[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 void
142 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
143                 const struct GNUNET_MessageHeader *message,
144                 const struct GNUNET_TRANSPORT_ATS_Information *ats,
145                 uint32_t ats_count)
146 {
147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148               "Received message of type %d from peer %s!\n",
149               ntohs (message->type), GNUNET_i2s (peer));
150
151   if ((MTYPE == ntohs (message->type)) &&
152       (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
153   {
154     ok = 0;
155     end (NULL, NULL);
156   }
157   else
158   {
159     GNUNET_break (0);
160     ok = 1;
161     end (NULL, NULL);
162   }
163 }
164
165
166 static size_t
167 notify_ready (void *cls, size_t size, void *buf)
168 {
169   struct PeerContext *p = cls;
170   struct GNUNET_MessageHeader *hdr;
171   char t;
172
173   th = NULL;
174   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
175               "Press <q> to quit or any key to transmit a message\n");
176
177   scanf("%c", &t);
178   if (t == 'q')
179   {
180     GNUNET_SCHEDULER_add_now(&end, NULL);
181     return 0;
182   }
183
184   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
185               "Transmitting message with %u bytes to peer %s\n",
186               sizeof (struct GNUNET_MessageHeader), GNUNET_i2s (&p->id));
187   GNUNET_assert (size >= 256);
188
189   if (buf != NULL)
190   {
191     hdr = buf;
192     hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
193     hdr->type = htons (MTYPE);
194   }
195
196   th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0, TIMEOUT,
197                                                &notify_ready, p1);
198
199   return sizeof (struct GNUNET_MessageHeader);
200 }
201
202
203 static void
204 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
205                 const struct GNUNET_TRANSPORT_ATS_Information *ats,
206                 uint32_t ats_count)
207 {
208   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n",
209               GNUNET_i2s (peer), cls);
210 }
211
212
213 static void
214 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
215 {
216   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n",
217               GNUNET_i2s (peer), cls);
218 }
219
220
221
222
223 struct PeerContext *
224 connect_to_peer (const char *cfgname, GNUNET_TRANSPORT_ReceiveCallback rec,
225                  GNUNET_TRANSPORT_NotifyConnect nc,
226                  GNUNET_TRANSPORT_NotifyDisconnect nd, void *cb_cls)
227 {
228   if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
229   {
230     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File not found: `%s' \n", cfgname);
231     return NULL;
232   }
233
234   struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
235
236   p->cfg = GNUNET_CONFIGURATION_create ();
237
238   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
239   if (GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME"))
240     GNUNET_CONFIGURATION_get_value_string (p->cfg, "PATHS", "SERVICEHOME",
241                                            &p->servicehome);
242   if (NULL != p->servicehome)
243     GNUNET_DISK_directory_remove (p->servicehome);
244   /*
245    * p->arm_proc =
246    * GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
247    * "gnunet-service-arm", "-c", cfgname,
248    * #if VERBOSE_PEERS
249    * "-L", "DEBUG",
250    * #else
251    * "-L", "ERROR",
252    * #endif
253    * NULL);
254    */
255   p->nc = nc;
256   p->nd = nd;
257   p->rec = rec;
258   if (cb_cls != NULL)
259     p->cb_cls = cb_cls;
260   else
261     p->cb_cls = p;
262
263   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service `%s'\n",
264               p->servicehome);
265   p->th =
266       GNUNET_TRANSPORT_connect (p->cfg, NULL, p, &notify_receive,
267                                 &notify_connect, &notify_disconnect);
268   GNUNET_assert (p->th != NULL);
269   return p;
270 }
271
272 static void
273 sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
274 {
275   send_task = GNUNET_SCHEDULER_NO_TASK;
276
277   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
278     return;
279
280   th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0, TIMEOUT,
281                                                &notify_ready, &p1);
282 }
283
284 static void
285 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
286 {
287   cc = NULL;
288   char *p1_c = strdup (GNUNET_i2s (&p1->id));
289
290   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers connected: %s <-> %s\n", p1_c,
291               GNUNET_i2s (&p2->id));
292   GNUNET_free (p1_c);
293
294   // FIXME: THIS IS REQUIRED! SEEMS TO BE A BUG!
295
296   send_task =
297       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL);
298 }
299
300 static void
301 run (void *cls, char *const *args, const char *cfgfile,
302      const struct GNUNET_CONFIGURATION_Handle *cfg)
303 {
304   die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
305
306   p1 = connect_to_peer (cfg_file_p1, &notify_receive, &notify_connect,
307                         &notify_disconnect, NULL);
308   p2 = connect_to_peer (cfg_file_p2, &notify_receive, &notify_connect,
309                         &notify_disconnect, NULL);
310
311   if ((p1 == NULL) || (p2 == NULL))
312   {
313     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
314     if (die_task != GNUNET_SCHEDULER_NO_TASK)
315       GNUNET_SCHEDULER_cancel (die_task);
316     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
317     return;
318   }
319
320   cc = GNUNET_TRANSPORT_TESTING_connect_peers (p1, p2, &testing_connect_cb,
321                                                NULL);
322 }
323
324
325 static int
326 check ()
327 {
328   static char *const argv[] = { "test-transport-api",
329     "-c",
330     "test_transport_api_data.conf",
331 #if VERBOSE
332     "-L", "DEBUG",
333 #endif
334     NULL
335   };
336   static struct GNUNET_GETOPT_CommandLineOption options[] = {
337     GNUNET_GETOPT_OPTION_END
338   };
339
340 #if WRITECONFIG
341   setTransportOptions ("test_transport_api_data.conf");
342 #endif
343   send_task = GNUNET_SCHEDULER_NO_TASK;
344
345   ok = 1;
346   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
347                       "util_connect_running_peers", "nohelp", options, &run,
348                       &ok);
349
350   return ok;
351 }
352
353 int
354 main (int argc, char *argv[])
355 {
356   int ret;
357
358   GNUNET_log_setup ("gnunet-transport-connect-running-peers",
359 #if VERBOSE
360                     "DEBUG",
361 #else
362                     "WARNING",
363 #endif
364                     NULL);
365
366
367   if (argc < 3)
368   {
369     fprintf (stderr,
370              "usage gnunet-transport-connect-running-peers <cfg_peer1> <cfg_peer2>\n");
371     return -1;
372   }
373   else
374   {
375     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Configuration file 1: `%s' \n",
376                 argv[1]);
377     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Configuration file 2: `%s'\n",
378                 argv[2]);
379   }
380
381   if (GNUNET_DISK_file_test (argv[1]) == GNUNET_NO)
382   {
383     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File not found: `%s' \n", argv[1]);
384     return -1;
385   }
386   if (GNUNET_DISK_file_test (argv[2]) == GNUNET_NO)
387   {
388     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File not found: `%s' \n", argv[2]);
389     return -1;
390   }
391
392   GNUNET_asprintf (&cfg_file_p1, argv[1]);
393   GNUNET_asprintf (&cfg_file_p2, argv[2]);
394
395   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
396               "Trying to connect peers, press control-d to stop... \n",
397               argv[1]);
398
399   ret = check ();
400
401   GNUNET_free (cfg_file_p1);
402   GNUNET_free (cfg_file_p2);
403   return ret;
404 }
405
406 /* end of gnunet-transport-connect-running-peers.c */