- fix compilation issue
[oweals/gnunet.git] / src / mesh / gnunet-mesh.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 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 /**
22  * @file mesh/gnunet-mesh.c
23  * @brief Print information about mesh tunnels and peers.
24  * @author Bartlomiej Polot
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_mesh_service.h"
29
30
31 /**
32  * Option -m.
33  */
34 static int monitor_connections;
35
36 /**
37  * Option -i.
38  */
39 static int get_info;
40
41 /**
42  * Option --tunnel
43  */
44 static char *tunnel_id;
45
46 /**
47  * Option --connection
48  */
49 static char *conn_id;
50
51 /**
52  * Option --channel
53  */
54 static char *channel_id;
55
56 /**
57  * Port to listen on (-p).
58  */
59 static uint32_t listen_port;
60
61 /**
62  * Peer to connect to.
63  */
64 static char *target_id;
65
66 /**
67  * Port to connect to
68  */
69 static uint32_t target_port;
70
71 /**
72  * Data pending in netcat mode.
73  */
74 size_t data_size;
75
76
77 /**
78  * Mesh handle.
79  */
80 static struct GNUNET_MESH_Handle *mh;
81
82 /**
83  * Channel handle.
84  */
85 static struct GNUNET_MESH_Channel *ch;
86
87 /**
88  * Shutdown task handle.
89  */
90 GNUNET_SCHEDULER_TaskIdentifier sd;
91
92
93
94 static void
95 listen_stdio (void);
96
97
98
99 /**
100  * Task run in monitor mode when the user presses CTRL-C to abort.
101  * Stops monitoring activity.
102  *
103  * @param cls Closure (unused).
104  * @param tc scheduler context
105  */
106 static void
107 shutdown_task (void *cls,
108                const struct GNUNET_SCHEDULER_TaskContext *tc)
109 {
110   if (NULL != ch)
111   {
112     GNUNET_MESH_channel_destroy (ch);
113     ch = NULL;
114   }
115   if (NULL != mh)
116   {
117     GNUNET_MESH_disconnect (mh);
118         mh = NULL;
119   }
120 }
121
122
123 /**
124  * Function called to notify a client about the connection
125  * begin ready to queue more data.  "buf" will be
126  * NULL and "size" zero if the connection was closed for
127  * writing in the meantime.
128  *
129  * FIXME
130  *
131  * @param cls closure
132  * @param size number of bytes available in buf
133  * @param buf where the callee should write the message
134  * @return number of bytes written to buf
135  */
136 size_t
137 data_ready (void *cls, size_t size, void *buf)
138 {
139   struct GNUNET_MessageHeader *msg;
140   size_t total_size;
141
142   if (NULL == buf || 0 == size)
143   {
144     GNUNET_SCHEDULER_shutdown();
145     return 0;
146   }
147
148   total_size = data_size + sizeof (struct GNUNET_MessageHeader);
149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
150   GNUNET_assert (size >= total_size);
151
152   msg = buf;
153   msg->size = htons (total_size);
154   msg->type = htons (GNUNET_MESSAGE_TYPE_MESH_CLI);
155   memcpy (&msg[1], cls, data_size);
156   listen_stdio ();
157
158   return total_size;
159 }
160
161
162 /**
163  * Task run in monitor mode when the user presses CTRL-C to abort.
164  * Stops monitoring activity.
165  *
166  * @param cls Closure (unused).
167  * @param tc scheduler context
168  */
169 static void
170 read_stdio (void *cls,
171             const struct GNUNET_SCHEDULER_TaskContext *tc)
172 {
173   char buf[60000];
174
175   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
176   {
177     return;
178   }
179
180   data_size = read (0, buf, 60000);
181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
182   {
183     struct GNUNET_HashCode hash;
184     GNUNET_CRYPTO_hash (buf, data_size, &hash);
185     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  cli SEND %p hash %s (%u)\n",
186                 buf, GNUNET_h2s_full (&hash), data_size);
187   }
188   if (data_size < 1)
189   {
190     GNUNET_SCHEDULER_shutdown();
191     return;
192   }
193   GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO,
194                                      GNUNET_TIME_UNIT_FOREVER_REL,
195                                      data_size
196                                      + sizeof (struct GNUNET_MessageHeader),
197                                      &data_ready, buf);
198 }
199
200
201 /**
202  * Start listening to stdin
203  */
204 static void
205 listen_stdio (void)
206 {
207   struct GNUNET_NETWORK_FDSet *rs;
208
209   rs = GNUNET_NETWORK_fdset_create ();
210   GNUNET_NETWORK_fdset_set_native (rs, 0);
211   GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
212                                GNUNET_TIME_UNIT_FOREVER_REL,
213                                rs, NULL,
214                                &read_stdio, NULL);
215   GNUNET_NETWORK_fdset_destroy (rs);
216 }
217
218
219 /**
220  * Function called whenever a channel is destroyed.  Should clean up
221  * any associated state.
222  *
223  * It must NOT call #GNUNET_MESH_channel_destroy on the channel.
224  *
225  * @param cls closure (set from #GNUNET_MESH_connect)
226  * @param channel connection to the other end (henceforth invalid)
227  * @param channel_ctx place where local state associated
228  *                   with the channel is stored
229  */
230 static void
231 channel_ended (void *cls,
232                const struct GNUNET_MESH_Channel *channel,
233                void *channel_ctx)
234 {
235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
236   GNUNET_break (channel == ch);
237   ch = NULL;
238   GNUNET_SCHEDULER_shutdown ();
239 }
240
241
242 /**
243  * Method called whenever another peer has added us to a channel
244  * the other peer initiated.
245  * Only called (once) upon reception of data with a message type which was
246  * subscribed to in #GNUNET_MESH_connect.
247  *
248  * A call to #GNUNET_MESH_channel_destroy causes te channel to be ignored. In
249  * this case the handler MUST return NULL.
250  *
251  * @param cls closure
252  * @param channel new handle to the channel
253  * @param initiator peer that started the channel
254  * @param port Port this channel is for.
255  * @param options MeshOption flag field, with all active option bits set to 1.
256  *
257  * @return initial channel context for the channel
258  *         (can be NULL -- that's not an error)
259  */
260 static void *
261 channel_incoming (void *cls,
262                   struct GNUNET_MESH_Channel * channel,
263                   const struct GNUNET_PeerIdentity * initiator,
264                   uint32_t port, enum GNUNET_MESH_ChannelOption options)
265 {
266   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267               "Incoming channel %p on port %u\n",
268               channel, port);
269   if (NULL != ch)
270   {
271     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
272     return NULL;
273   }
274   if (0 == listen_port)
275   {
276     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
277     return NULL;
278   }
279   ch = channel;
280   listen_stdio ();
281   return NULL;
282 }
283
284
285
286 /**
287  * Call MESH's monitor API, get info of one connection.
288  *
289  * @param cls Closure (unused).
290  * @param tc TaskContext
291  */
292 static void
293 create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
294 {
295   struct GNUNET_PeerIdentity pid;
296   enum GNUNET_MESH_ChannelOption opt;
297
298   GNUNET_assert (NULL == ch);
299
300   if (GNUNET_OK !=
301       GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
302                                                   strlen (target_id),
303                                                   &pid.public_key))
304   {
305     FPRINTF (stderr,
306              _("Invalid target `%s'\n"),
307              target_id);
308     GNUNET_SCHEDULER_shutdown ();
309     return;
310   }
311   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
312   opt = GNUNET_MESH_OPTION_DEFAULT | GNUNET_MESH_OPTION_RELIABLE;
313   ch = GNUNET_MESH_channel_create (mh, NULL, &pid, target_port, opt);
314   listen_stdio ();
315 }
316
317
318 /**
319  * Function called whenever a message is received.
320  *
321  * Each time the function must call #GNUNET_MESH_receive_done on the channel
322  * in order to receive the next message. This doesn't need to be immediate:
323  * can be delayed if some processing is done on the message.
324  *
325  * @param cls Closure (set from #GNUNET_MESH_connect).
326  * @param channel Connection to the other end.
327  * @param channel_ctx Place to store local state associated with the channel.
328  * @param message The actual message.
329  * @return #GNUNET_OK to keep the channel open,
330  *         #GNUNET_SYSERR to close it (signal serious error).
331  */
332 static int
333 data_callback (void *cls,
334                struct GNUNET_MESH_Channel *channel,
335                void **channel_ctx,
336                const struct GNUNET_MessageHeader *message)
337 {
338   uint16_t len;
339   GNUNET_break (ch == channel);
340
341   len = ntohs (message->size) - sizeof (*message);
342   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
343   write (1, (char *) &message[1], len);
344   {
345     struct GNUNET_HashCode hash;
346
347     GNUNET_CRYPTO_hash (message, ntohs (message->size), &hash);
348     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  api RECV %p hash %s (%u)\n",
349                 message, GNUNET_h2s_full (&hash), ntohs (message->size));
350     GNUNET_CRYPTO_hash (&message[1], len, &hash);
351     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  cli RECV %p hash %s (%u)\n",
352                 &message[1], GNUNET_h2s_full (&hash), len);
353   }
354   return GNUNET_OK;
355 }
356
357
358 /**
359  * Method called to retrieve information about each tunnel the mesh peer
360  * is aware of.
361  *
362  * @param cls Closure.
363  * @param tunnel_number Tunnel number.
364  * @param origin that started the tunnel (owner).
365  * @param target other endpoint of the tunnel
366  */
367 void /* FIXME static */
368 tunnels_callback (void *cls,
369                   uint32_t tunnel_number,
370                   const struct GNUNET_PeerIdentity *origin,
371                   const struct GNUNET_PeerIdentity *target)
372 {
373   FPRINTF (stdout, "Tunnel %s [%u]\n",
374            GNUNET_i2s_full (origin), tunnel_number);
375   FPRINTF (stdout, "\n");
376 }
377
378
379 /**
380  * Method called to retrieve information about each tunnel the mesh peer
381  * is aware of.
382  *
383  * @param cls Closure.
384  * @param peer Peer in the tunnel's tree.
385  * @param parent Parent of the current peer. All 0 when peer is root.
386  *
387  */
388 void /* FIXME static */
389 tunnel_callback (void *cls,
390                  const struct GNUNET_PeerIdentity *peer,
391                  const struct GNUNET_PeerIdentity *parent)
392 {
393 }
394
395
396 /**
397  * Call MESH's monitor API, get all tunnels known to peer.
398  *
399  * @param cls Closure (unused).
400  * @param tc TaskContext
401  */
402 static void
403 get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
404 {
405   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
406   {
407     return;
408   }
409 //   GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL);
410   if (GNUNET_YES != monitor_connections)
411   {
412     GNUNET_SCHEDULER_shutdown();
413   }
414 }
415
416
417 /**
418  * Call MESH's monitor API, get info of one tunnel.
419  *
420  * @param cls Closure (unused).
421  * @param tc TaskContext
422  */
423 static void
424 show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
425 {
426   struct GNUNET_PeerIdentity pid;
427
428   if (GNUNET_OK !=
429       GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
430                                                   strlen (tunnel_id),
431                                                   &pid.public_key))
432   {
433     fprintf (stderr,
434              _("Invalid tunnel owner `%s'\n"),
435              tunnel_id);
436     GNUNET_SCHEDULER_shutdown();
437     return;
438   }
439 //   GNUNET_MESH_show_tunnel (mh, &pid, 0, tunnel_callback, NULL);
440 }
441
442
443 /**
444  * Call MESH's monitor API, get info of one channel.
445  *
446  * @param cls Closure (unused).
447  * @param tc TaskContext
448  */
449 static void
450 show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
451 {
452
453 }
454
455
456 /**
457  * Call MESH's monitor API, get info of one connection.
458  *
459  * @param cls Closure (unused).
460  * @param tc TaskContext
461  */
462 static void
463 show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
464 {
465
466 }
467
468
469 /**
470  * Main function that will be run by the scheduler.
471  *
472  * @param cls closure
473  * @param args remaining command-line arguments
474  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
475  * @param cfg configuration
476  */
477 static void
478 run (void *cls, char *const *args, const char *cfgfile,
479      const struct GNUNET_CONFIGURATION_Handle *cfg)
480 {
481   GNUNET_MESH_InboundChannelNotificationHandler *newch = NULL;
482   GNUNET_MESH_ChannelEndHandler *endch = NULL;
483   static const struct GNUNET_MESH_MessageHandler handlers[] = {
484     {&data_callback, GNUNET_MESSAGE_TYPE_MESH_CLI, 0},
485     {NULL, 0, 0} /* FIXME add option to monitor msg types */
486   };
487   static uint32_t *ports = NULL;
488   /* FIXME add option to monitor apps */
489
490   target_id = args[0];
491   target_port = args[0] && args[1] ? atoi(args[1]) : 0;
492   if ( (0 != get_info
493         || 0 != monitor_connections
494         || NULL != tunnel_id
495         || NULL != conn_id
496         || NULL != channel_id)
497        && target_id != NULL)
498   {
499     FPRINTF (stderr, _("You must NOT give a TARGET when using options\n"));
500     return;
501   }
502
503   if (NULL != target_id)
504   {
505     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
506                 "Creating channel to %s\n",
507                 target_id);
508     GNUNET_SCHEDULER_add_now (&create_channel, NULL);
509     endch = &channel_ended;
510   }
511   else if (0 != listen_port)
512   {
513     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
514     newch = &channel_incoming;
515     endch = &channel_ended;
516     ports = GNUNET_malloc (sizeof (uint32_t) * 2);
517     ports[0] = listen_port;
518   }
519   else if (NULL != tunnel_id)
520   {
521     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
522     GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
523   }
524   else if (NULL != channel_id)
525   {
526     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
527     GNUNET_SCHEDULER_add_now (&show_channel, NULL);
528   }
529   else if (NULL != conn_id)
530   {
531     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
532     GNUNET_SCHEDULER_add_now (&show_connection, NULL);
533   }
534   else if (GNUNET_YES == get_info)
535   {
536     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
537     GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
538   }
539   else
540   {
541     FPRINTF (stderr, "No action requested\n");
542     return;
543   }
544
545   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mesh\n");
546   mh = GNUNET_MESH_connect (cfg,
547                             NULL, /* cls */
548                             newch, /* new channel */
549                             endch, /* cleaner */
550                             handlers,
551                             ports);
552   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
553   if (NULL == mh)
554     GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
555   else
556     sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
557                                        shutdown_task, NULL);
558
559 }
560
561
562 /**
563  * The main function to obtain peer information.
564  *
565  * @param argc number of arguments from the command line
566  * @param argv command line arguments
567  * @return 0 ok, 1 on error
568  */
569 int
570 main (int argc, char *const *argv)
571 {
572   int res;
573   const char helpstr[] = "Create channels and retreive info about meshs status.";
574   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
575     {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
576      gettext_noop ("provide information about a particular channel"),
577      GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
578     {'b', "connection", "TUNNEL_ID:CONNECTION_ID",
579      gettext_noop ("provide information about a particular connection"),
580      GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
581     {'i', "info", NULL,
582      gettext_noop ("provide information about all tunnels"),
583      GNUNET_NO, &GNUNET_GETOPT_set_one, &get_info},
584     {'m', "monitor", NULL,
585      gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */
586      GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections},
587     {'p', "port", NULL,
588      gettext_noop ("port to listen to (default; 0)"),
589      GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
590     {'t', "tunnel", "TUNNEL_ID",
591      gettext_noop ("provide information about a particular tunnel"),
592      GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
593     GNUNET_GETOPT_OPTION_END
594   };
595
596   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
597     return 2;
598
599   res = GNUNET_PROGRAM_run (argc, argv, "gnunet-mesh (OPTIONS | TARGET PORT)",
600                             gettext_noop (helpstr),
601                             options, &run, NULL);
602
603   GNUNET_free ((void *) argv);
604
605   if (GNUNET_OK == res)
606     return 0;
607   else
608     return 1;
609 }
610
611 /* end of gnunet-mesh.c */