-create channel
[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
73 /**
74  * Mesh handle.
75  */
76 static struct GNUNET_MESH_Handle *mh;
77
78 static struct GNUNET_MESH_Channel *ch;
79
80 /**
81  * Shutdown task handle.
82  */
83 GNUNET_SCHEDULER_TaskIdentifier sd;
84
85 /**
86  * Task run in monitor mode when the user presses CTRL-C to abort.
87  * Stops monitoring activity.
88  *
89  * @param cls Closure (unused).
90  * @param tc scheduler context
91  */
92 static void
93 shutdown_task (void *cls,
94                const struct GNUNET_SCHEDULER_TaskContext *tc)
95 {
96   if (NULL != ch)
97   {
98     GNUNET_MESH_channel_destroy (ch);
99     ch = NULL;
100   }
101   if (NULL != mh)
102   {
103     GNUNET_MESH_disconnect (mh);
104         mh = NULL;
105   }
106 }
107
108
109 /**
110  * Function called whenever a channel is destroyed.  Should clean up
111  * any associated state.
112  *
113  * It must NOT call #GNUNET_MESH_channel_destroy on the channel.
114  *
115  * @param cls closure (set from #GNUNET_MESH_connect)
116  * @param channel connection to the other end (henceforth invalid)
117  * @param channel_ctx place where local state associated
118  *                   with the channel is stored
119  */
120 static void
121 channel_ended (void *cls,
122                const struct GNUNET_MESH_Channel *channel,
123                void *channel_ctx)
124 {
125   FPRINTF (stdout, "Channel ended!\n");
126   GNUNET_break (channel == ch);
127   GNUNET_SCHEDULER_shutdown ();
128 }
129
130
131 /**
132  * Method called whenever another peer has added us to a channel
133  * the other peer initiated.
134  * Only called (once) upon reception of data with a message type which was
135  * subscribed to in #GNUNET_MESH_connect.
136  *
137  * A call to #GNUNET_MESH_channel_destroy causes te channel to be ignored. In
138  * this case the handler MUST return NULL.
139  *
140  * @param cls closure
141  * @param channel new handle to the channel
142  * @param initiator peer that started the channel
143  * @param port Port this channel is for.
144  * @param options MeshOption flag field, with all active option bits set to 1.
145  *
146  * @return initial channel context for the channel
147  *         (can be NULL -- that's not an error)
148  */
149 void *
150 channel_incoming (void *cls,
151                   struct GNUNET_MESH_Channel * channel,
152                   const struct GNUNET_PeerIdentity * initiator,
153                   uint32_t port, enum MeshOption options)
154 {
155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Incoming channel on port %u\n", port);
156   if (NULL != ch)
157   {
158     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
159     return NULL;
160   }
161   if (0 == listen_port)
162   {
163     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
164     return NULL;
165   }
166   ch = channel;
167   return NULL;
168 }
169
170
171
172 /**
173  * Call MESH's monitor API, get info of one connection.
174  *
175  * @param cls Closure (unused).
176  * @param tc TaskContext
177  */
178 static void
179 create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
180 {
181   struct GNUNET_PeerIdentity pid;
182
183   GNUNET_assert (NULL == ch);
184
185   if (GNUNET_OK !=
186       GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
187                                                   strlen (target_id),
188                                                   &pid.public_key))
189   {
190     FPRINTF (stderr,
191              _("Invalid target `%s'\n"),
192              target_id);
193     GNUNET_SCHEDULER_shutdown ();
194     return;
195   }
196   GNUNET_MESH_channel_create (mh, NULL, &pid, GNUNET_MESSAGE_TYPE_MESH_CLI,
197                               GNUNET_MESH_OPTION_DEFAULT);
198 }
199
200
201 /**
202  * Function called whenever a message is received.
203  *
204  * Each time the function must call #GNUNET_MESH_receive_done on the channel
205  * in order to receive the next message. This doesn't need to be immediate:
206  * can be delayed if some processing is done on the message.
207  *
208  * @param cls Closure (set from #GNUNET_MESH_connect).
209  * @param channel Connection to the other end.
210  * @param channel_ctx Place to store local state associated with the channel.
211  * @param message The actual message.
212  * @return #GNUNET_OK to keep the channel open,
213  *         #GNUNET_SYSERR to close it (signal serious error).
214  */
215 int
216 data_callback (void *cls,
217                struct GNUNET_MESH_Channel *channel,
218                void **channel_ctx,
219                const struct GNUNET_MessageHeader *message)
220 {
221   int16_t len;
222   GNUNET_break (ch == channel);
223
224   len = ntohs (message->size) - sizeof (*message);
225   FPRINTF (stdout, "%.*s", len, (char *) &message[1]);
226   return GNUNET_OK;
227 }
228
229
230 /**
231  * Method called to retrieve information about each tunnel the mesh peer
232  * is aware of.
233  *
234  * @param cls Closure.
235  * @param tunnel_number Tunnel number.
236  * @param origin that started the tunnel (owner).
237  * @param target other endpoint of the tunnel
238  */
239 void /* FIXME static */
240 tunnels_callback (void *cls,
241                   uint32_t tunnel_number,
242                   const struct GNUNET_PeerIdentity *origin,
243                   const struct GNUNET_PeerIdentity *target)
244 {
245   FPRINTF (stdout, "Tunnel %s [%u]\n",
246            GNUNET_i2s_full (origin), tunnel_number);
247   FPRINTF (stdout, "\n");
248 }
249
250
251 /**
252  * Method called to retrieve information about each tunnel the mesh peer
253  * is aware of.
254  *
255  * @param cls Closure.
256  * @param peer Peer in the tunnel's tree.
257  * @param parent Parent of the current peer. All 0 when peer is root.
258  *
259  */
260 void /* FIXME static */
261 tunnel_callback (void *cls,
262                  const struct GNUNET_PeerIdentity *peer,
263                  const struct GNUNET_PeerIdentity *parent)
264 {
265 }
266
267
268 /**
269  * Call MESH's monitor API, get all tunnels known to peer.
270  *
271  * @param cls Closure (unused).
272  * @param tc TaskContext
273  */
274 static void
275 get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
276 {
277   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
278   {
279     return;
280   }
281 //   GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL);
282   if (GNUNET_YES != monitor_connections)
283   {
284     GNUNET_SCHEDULER_shutdown();
285   }
286 }
287
288
289 /**
290  * Call MESH's monitor API, get info of one tunnel.
291  *
292  * @param cls Closure (unused).
293  * @param tc TaskContext
294  */
295 static void
296 show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
297 {
298   struct GNUNET_PeerIdentity pid;
299
300   if (GNUNET_OK !=
301       GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
302                                                   strlen (tunnel_id),
303                                                   &pid.public_key))
304   {
305     fprintf (stderr,
306              _("Invalid tunnel owner `%s'\n"),
307              tunnel_id);
308     GNUNET_SCHEDULER_shutdown();
309     return;
310   }
311 //   GNUNET_MESH_show_tunnel (mh, &pid, 0, tunnel_callback, NULL);
312 }
313
314
315 /**
316  * Call MESH's monitor API, get info of one channel.
317  *
318  * @param cls Closure (unused).
319  * @param tc TaskContext
320  */
321 static void
322 show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
323 {
324
325 }
326
327
328 /**
329  * Call MESH's monitor API, get info of one connection.
330  *
331  * @param cls Closure (unused).
332  * @param tc TaskContext
333  */
334 static void
335 show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
336 {
337
338 }
339
340
341 /**
342  * Main function that will be run by the scheduler.
343  *
344  * @param cls closure
345  * @param args remaining command-line arguments
346  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
347  * @param cfg configuration
348  */
349 static void
350 run (void *cls, char *const *args, const char *cfgfile,
351      const struct GNUNET_CONFIGURATION_Handle *cfg)
352 {
353   GNUNET_MESH_InboundChannelNotificationHandler *newch = NULL;
354   GNUNET_MESH_ChannelEndHandler *endch = NULL;
355   static const struct GNUNET_MESH_MessageHandler handlers[] = {
356     {&data_callback, GNUNET_MESSAGE_TYPE_MESH_CLI, 0},
357     {NULL, 0, 0} /* FIXME add option to monitor msg types */
358   };
359   /* FIXME add option to monitor apps */
360
361   target_id = args[0];
362   target_port = args[0] && args[1] ? atoi(args[1]) : 0;
363   if ( (0 != get_info
364         || 0 != monitor_connections
365         || NULL != tunnel_id
366         || NULL != conn_id
367         || NULL != channel_id)
368        && target_id != NULL)
369   {
370     FPRINTF (stderr, _("You must NOT give a TARGET when using options\n"));
371     return;
372   }
373
374   if (NULL != target_id)
375   {
376     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377                 "Creating channel to %s\n",
378                 target_id);
379     GNUNET_SCHEDULER_add_now (&create_channel, NULL);
380     endch = &channel_ended;
381   }
382   else if (0 != listen_port)
383   {
384     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
385     newch = &channel_incoming;
386   }
387   else if (NULL != tunnel_id)
388   {
389     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
390     GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
391   }
392   else if (NULL != channel_id)
393   {
394     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
395     GNUNET_SCHEDULER_add_now (&show_channel, NULL);
396   }
397   else if (NULL != conn_id)
398   {
399     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
400     GNUNET_SCHEDULER_add_now (&show_connection, NULL);
401   }
402   else if (GNUNET_YES == get_info)
403   {
404     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
405     GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
406   }
407   else
408   {
409     FPRINTF (stderr, "No action requested\n");
410     return;
411   }
412
413   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mesh\n");
414   mh = GNUNET_MESH_connect (cfg,
415                             NULL, /* cls */
416                             newch, /* new channel */
417                             endch, /* cleaner */
418                             handlers,
419                             NULL);
420   FPRINTF (stdout, "Done\n");
421   if (NULL == mh)
422     GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
423   else
424     sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
425                                        shutdown_task, NULL);
426
427 }
428
429
430 /**
431  * The main function to obtain peer information.
432  *
433  * @param argc number of arguments from the command line
434  * @param argv command line arguments
435  * @return 0 ok, 1 on error
436  */
437 int
438 main (int argc, char *const *argv)
439 {
440   int res;
441   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
442     {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
443      gettext_noop ("provide information about a particular channel"),
444      GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
445     {'b', "connection", "TUNNEL_ID:CONNECTION_ID",
446      gettext_noop ("provide information about a particular connection"),
447      GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
448     {'i', "info", NULL,
449      gettext_noop ("provide information about all tunnels"),
450      GNUNET_NO, &GNUNET_GETOPT_set_one, &get_info},
451     {'m', "monitor", NULL,
452      gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */
453      GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections},
454     {'p', "port", NULL,
455      gettext_noop ("port to listen to (default; 0)"),
456      GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
457     {'t', "tunnel", "TUNNEL_ID",
458      gettext_noop ("provide information about a particular tunnel"),
459      GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
460     GNUNET_GETOPT_OPTION_END
461   };
462
463   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
464     return 2;
465
466   res = GNUNET_PROGRAM_run (argc, argv, "gnunet-mesh (OPTIONS | TARGET PORT)",
467                       gettext_noop
468                       ("Create channels and retreive info about meshs status."),
469                       options, &run, NULL);
470
471   GNUNET_free ((void *) argv);
472
473   if (GNUNET_OK == res)
474     return 0;
475   else
476     return 1;
477 }
478
479 /* end of gnunet-mesh.c */