Merge branch 'schanzen/argon_pow'
[oweals/gnunet.git] / src / cadet / gnunet-cadet.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2017, 2019 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 /**
22  * @file cadet/gnunet-cadet.c
23  * @brief Print information about cadet tunnels and peers.
24  * @author Bartlomiej Polot
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_cadet_service.h"
30 #include "cadet.h"
31
32 #define STREAM_BUFFER_SIZE 1024 // Pakets
33
34 /**
35  * Option -P.
36  */
37 static int request_peers;
38
39 /**
40  * Option --peer
41  */
42 static char *peer_id;
43
44 /**
45  * Option -T.
46  */
47 static int request_tunnels;
48
49 /**
50  * Option --connection
51  */
52 static char *conn_id;
53
54 /**
55  * Option --channel
56  */
57 static char *channel_id;
58
59 /**
60  * Port to listen on (-o).
61  */
62 static char *listen_port;
63
64 /**
65  * Request echo service
66  */
67 static int echo;
68
69 /**
70  * Time of last echo request.
71  */
72 static struct GNUNET_TIME_Absolute echo_time;
73
74 /**
75  * Task for next echo request.
76  */
77 static struct GNUNET_SCHEDULER_Task *echo_task;
78
79 /**
80  * Peer to connect to.
81  */
82 static char *target_id;
83
84 /**
85  * Port to connect to
86  */
87 static char *target_port = "default";
88
89 /**
90  * Cadet handle.
91  */
92 static struct GNUNET_CADET_Handle *mh;
93
94 /**
95  * Our configuration.
96  */
97 static const struct GNUNET_CONFIGURATION_Handle *my_cfg;
98
99 /**
100  * Active get path operation.
101  */
102 static struct GNUNET_CADET_GetPath *gpo;
103
104 /**
105  * Active peer listing operation.
106  */
107 static struct GNUNET_CADET_PeersLister *plo;
108
109 /**
110  * Active tunnel listing operation.
111  */
112 static struct GNUNET_CADET_ListTunnels *tio;
113
114 /**
115  * Channel handle.
116  */
117 static struct GNUNET_CADET_Channel *ch;
118
119 /**
120  * HashCode of the given port string
121  */
122 static struct GNUNET_HashCode porthash;
123
124 /**
125  * Data structure for ongoing reception of incoming virtual circuits.
126  */
127 struct GNUNET_CADET_Port *lp;
128
129 /**
130  * Task for reading from stdin.
131  */
132 static struct GNUNET_SCHEDULER_Task *rd_task;
133
134 /**
135  * Task for main job.
136  */
137 static struct GNUNET_SCHEDULER_Task *job;
138
139 static unsigned int sent_pkt;
140
141
142 /**
143  * Wait for input on STDIO and send it out over the #ch.
144  */
145 static void
146 listen_stdio (void);
147
148
149 /**
150  * Convert encryption status to human readable string.
151  *
152  * @param status Encryption status.
153  *
154  * @return Human readable string.
155  */
156 static const char *
157 enc_2s (uint16_t status)
158 {
159   switch (status)
160   {
161   case 0:
162     return "NULL ";
163
164   case 1:
165     return "KSENT";
166
167   case 2:
168     return "KRECV";
169
170   case 3:
171     return "READY";
172
173   default:
174     return "";
175   }
176 }
177
178
179 /**
180  * Convert connection status to human readable string.
181  *
182  * @param status Connection status.
183  *
184  * @return Human readable string.
185  */
186 static const char *
187 conn_2s (uint16_t status)
188 {
189   switch (status)
190   {
191   case 0:
192     return "NEW  ";
193
194   case 1:
195     return "SRCH ";
196
197   case 2:
198     return "WAIT ";
199
200   case 3:
201     return "READY";
202
203   case 4:
204     return "SHUTD";
205
206   default:
207     return "";
208   }
209 }
210
211
212 /**
213  * Task to shut down this application.
214  *
215  * @param cls Closure (unused).
216  */
217 static void
218 shutdown_task (void *cls)
219 {
220   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
221   if (NULL != lp)
222   {
223     GNUNET_CADET_close_port (lp);
224     lp = NULL;
225   }
226   if (NULL != ch)
227   {
228     GNUNET_CADET_channel_destroy (ch);
229     ch = NULL;
230   }
231   if (NULL != gpo)
232   {
233     GNUNET_CADET_get_path_cancel (gpo);
234     gpo = NULL;
235   }
236   if (NULL != plo)
237   {
238     GNUNET_CADET_list_peers_cancel (plo);
239     plo = NULL;
240   }
241   if (NULL != tio)
242   {
243     GNUNET_CADET_list_tunnels_cancel (tio);
244     tio = NULL;
245   }
246   if (NULL != mh)
247   {
248     GNUNET_CADET_disconnect (mh);
249     mh = NULL;
250   }
251   if (NULL != rd_task)
252   {
253     GNUNET_SCHEDULER_cancel (rd_task);
254     rd_task = NULL;
255   }
256   if (NULL != echo_task)
257   {
258     GNUNET_SCHEDULER_cancel (echo_task);
259     echo_task = NULL;
260   }
261   if (NULL != job)
262   {
263     GNUNET_SCHEDULER_cancel (job);
264     job = NULL;
265   }
266 }
267
268
269 void
270 mq_cb (void *cls)
271 {
272   listen_stdio ();
273 }
274
275
276 /**
277  * Task run in stdio mode, after some data is available at stdin.
278  *
279  * @param cls Closure (unused).
280  */
281 static void
282 read_stdio (void *cls)
283 {
284   struct GNUNET_MQ_Envelope *env;
285   struct GNUNET_MessageHeader *msg;
286   char buf[60000];
287   ssize_t data_size;
288
289   rd_task = NULL;
290   data_size = read (0, buf, 60000);
291   if (data_size < 1)
292   {
293     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294                 "read() returned  %s\n",
295                 strerror (errno));
296     GNUNET_SCHEDULER_shutdown ();
297     return;
298   }
299   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300               "Read %u bytes from stdio\n",
301               (unsigned int) data_size);
302   env = GNUNET_MQ_msg_extra (msg, data_size, GNUNET_MESSAGE_TYPE_CADET_CLI);
303   GNUNET_memcpy (&msg[1], buf, data_size);
304   GNUNET_MQ_send (GNUNET_CADET_get_mq (ch), env);
305
306   sent_pkt++;
307
308   if (GNUNET_NO == echo)
309   {
310     // Use MQ's notification if too much data of stdin is pooring in too fast.
311     if (STREAM_BUFFER_SIZE < sent_pkt)
312     {
313       GNUNET_MQ_notify_sent (env, mq_cb, cls);
314       sent_pkt = 0;
315     }
316     else
317     {
318       listen_stdio ();
319     }
320   }
321   else
322   {
323     echo_time = GNUNET_TIME_absolute_get ();
324   }
325 }
326
327
328 /**
329  * Wait for input on STDIO and send it out over the #ch.
330  */
331 static void
332 listen_stdio ()
333 {
334   struct GNUNET_NETWORK_FDSet *rs;
335
336   /* FIXME: why use 'rs' here, seems overly complicated... */
337   rs = GNUNET_NETWORK_fdset_create ();
338   GNUNET_NETWORK_fdset_set_native (rs, 0);  /* STDIN */
339   rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
340                                          GNUNET_TIME_UNIT_FOREVER_REL,
341                                          rs,
342                                          NULL,
343                                          &read_stdio,
344                                          NULL);
345   GNUNET_NETWORK_fdset_destroy (rs);
346 }
347
348
349 /**
350  * Function called whenever a channel is destroyed.  Should clean up
351  * any associated state.
352  *
353  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
354  *
355  * @param cls closure
356  * @param channel connection to the other end (henceforth invalid)
357  */
358 static void
359 channel_ended (void *cls, const struct GNUNET_CADET_Channel *channel)
360 {
361   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
362   GNUNET_assert (channel == ch);
363   ch = NULL;
364   GNUNET_SCHEDULER_shutdown ();
365 }
366
367
368 /**
369  * Method called whenever another peer has added us to a channel
370  * the other peer initiated.
371  * Only called (once) upon reception of data with a message type which was
372  * subscribed to in #GNUNET_CADET_connect.
373  *
374  * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
375  * In this case the handler MUST return NULL.
376  *
377  * @param cls closure
378  * @param channel new handle to the channel
379  * @param initiator peer that started the channel
380  * @return initial channel context for the channel, we use @a channel
381  */
382 static void *
383 channel_incoming (void *cls,
384                   struct GNUNET_CADET_Channel *channel,
385                   const struct GNUNET_PeerIdentity *initiator)
386 {
387   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
388               "Incoming connection from %s\n",
389               GNUNET_i2s_full (initiator));
390   GNUNET_assert (NULL == ch);
391   GNUNET_assert (NULL != lp);
392   GNUNET_CADET_close_port (lp);
393   lp = NULL;
394   ch = channel;
395   if (GNUNET_NO == echo)
396     listen_stdio ();
397   return channel;
398 }
399
400
401 /**
402  * @brief Send an echo request to the remote peer.
403  *
404  * @param cls Closure (NULL).
405  */
406 static void
407 send_echo (void *cls)
408 {
409   struct GNUNET_MQ_Envelope *env;
410   struct GNUNET_MessageHeader *msg;
411
412   echo_task = NULL;
413   if (NULL == ch)
414     return;
415   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_CLI);
416   GNUNET_MQ_send (GNUNET_CADET_get_mq (ch), env);
417 }
418
419
420 /**
421  * Check data message sanity. Does nothing so far (all messages are OK).
422  *
423  * @param cls Closure (unused).
424  * @param message The message to check.
425  * @return #GNUNET_OK to keep the channel open,
426  *         #GNUNET_SYSERR to close it (signal serious error).
427  */
428 static int
429 check_data (void *cls, const struct GNUNET_MessageHeader *message)
430 {
431   return GNUNET_OK; /* all is well-formed */
432 }
433
434
435 /**
436  * Function called whenever a message is received.
437  *
438  * Each time the function must call #GNUNET_CADET_receive_done on the channel
439  * in order to receive the next message. This doesn't need to be immediate:
440  * can be delayed if some processing is done on the message.
441  *
442  * @param cls NULL
443  * @param message The actual message.
444  */
445 static void
446 handle_data (void *cls, const struct GNUNET_MessageHeader *message)
447 {
448   size_t payload_size = ntohs (message->size) - sizeof(*message);
449   uint16_t len;
450   ssize_t done;
451   uint16_t off;
452   const char *buf;
453
454   GNUNET_CADET_receive_done (ch);
455   if (GNUNET_YES == echo)
456   {
457     if (NULL != listen_port)
458     {
459       struct GNUNET_MQ_Envelope *env;
460       struct GNUNET_MessageHeader *msg;
461
462       env =
463         GNUNET_MQ_msg_extra (msg, payload_size, GNUNET_MESSAGE_TYPE_CADET_CLI);
464       GNUNET_memcpy (&msg[1], &message[1], payload_size);
465       GNUNET_MQ_send (GNUNET_CADET_get_mq (ch), env);
466       return;
467     }
468     else
469     {
470       struct GNUNET_TIME_Relative latency;
471
472       latency = GNUNET_TIME_absolute_get_duration (echo_time);
473       echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
474       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
475                   "time: %s\n",
476                   GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
477       echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
478                                                 &send_echo,
479                                                 NULL);
480     }
481   }
482
483   len = ntohs (message->size) - sizeof(*message);
484   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
485   buf = (const char *) &message[1];
486   off = 0;
487   while (off < len)
488   {
489     done = write (1, &buf[off], len - off);
490     if (done <= 0)
491     {
492       if (-1 == done)
493         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
494       GNUNET_SCHEDULER_shutdown ();
495       return;
496     }
497     off += done;
498   }
499 }
500
501
502 /**
503  * Method called to retrieve information about all peers in CADET, called
504  * once per peer.
505  *
506  * After last peer has been reported, an additional call with NULL is done.
507  *
508  * @param cls Closure.
509  * @param ple information about peer, or NULL on "EOF".
510  */
511 static void
512 peers_callback (void *cls, const struct GNUNET_CADET_PeerListEntry *ple)
513 {
514   if (NULL == ple)
515   {
516     plo = NULL;
517     GNUNET_SCHEDULER_shutdown ();
518     return;
519   }
520   fprintf (stdout,
521            "%s tunnel: %c, paths: %u\n",
522            GNUNET_i2s_full (&ple->peer),
523            ple->have_tunnel ? 'Y' : 'N',
524            ple->n_paths);
525 }
526
527
528 /**
529  * Method called to retrieve information about paths to a specific peer
530  * known to the service.
531  *
532  * @param cls Closure.
533  * @param ppd path detail
534  */
535 static void
536 path_callback (void *cls, const struct GNUNET_CADET_PeerPathDetail *ppd)
537 {
538   if (NULL == ppd)
539   {
540     gpo = NULL;
541     GNUNET_SCHEDULER_shutdown ();
542     return;
543   }
544   fprintf (stdout, "Path of length %u: ", ppd->path_length);
545   for (unsigned int i = 0; i < ppd->path_length; i++)
546     fprintf (stdout,
547              (i == ppd->target_offset) ? "*%s* " : "%s ",
548              GNUNET_i2s (&ppd->path[i]));
549   fprintf (stdout, "\n");
550 }
551
552
553 /**
554  * Method called to retrieve information about all tunnels in CADET.
555  *
556  * @param cls Closure.
557  * @param td tunnel details
558  */
559 static void
560 tunnels_callback (void *cls, const struct GNUNET_CADET_TunnelDetails *td)
561 {
562   if (NULL == td)
563   {
564     tio = NULL;
565     GNUNET_SCHEDULER_shutdown ();
566     return;
567   }
568   fprintf (stdout,
569            "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
570            GNUNET_i2s_full (&td->peer),
571            enc_2s (td->estate),
572            conn_2s (td->cstate),
573            td->channels,
574            td->connections);
575 }
576
577
578 /**
579  * Call CADET's meta API, get all peers known to a peer.
580  *
581  * @param cls Closure (unused).
582  */
583 static void
584 get_peers (void *cls)
585 {
586   job = NULL;
587   plo = GNUNET_CADET_list_peers (my_cfg, &peers_callback, NULL);
588 }
589
590
591 /**
592  * Call CADET's monitor API, get info of one peer.
593  *
594  * @param cls Closure (unused).
595  */
596 static void
597 show_peer (void *cls)
598 {
599   struct GNUNET_PeerIdentity pid;
600
601   job = NULL;
602   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
603                                                                strlen (peer_id),
604                                                                &pid.public_key))
605   {
606     fprintf (stderr, _ ("Invalid peer ID `%s'\n"), peer_id);
607     GNUNET_SCHEDULER_shutdown ();
608     return;
609   }
610   gpo = GNUNET_CADET_get_path (my_cfg, &pid, &path_callback, NULL);
611 }
612
613
614 /**
615  * Call CADET's meta API, get all tunnels known to a peer.
616  *
617  * @param cls Closure (unused).
618  */
619 static void
620 get_tunnels (void *cls)
621 {
622   job = NULL;
623   tio = GNUNET_CADET_list_tunnels (my_cfg, &tunnels_callback, NULL);
624 }
625
626
627 /**
628  * Call CADET's monitor API, get info of one channel.
629  *
630  * @param cls Closure (unused).
631  */
632 static void
633 show_channel (void *cls)
634 {
635   job = NULL;
636   GNUNET_break (0);
637 }
638
639
640 /**
641  * Call CADET's monitor API, get info of one connection.
642  *
643  * @param cls Closure (unused).
644  */
645 static void
646 show_connection (void *cls)
647 {
648   job = NULL;
649   GNUNET_break (0);
650 }
651
652
653 /**
654  * Main function that will be run by the scheduler.
655  *
656  * @param cls closure
657  * @param args remaining command-line arguments
658  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
659  * @param cfg configuration
660  */
661 static void
662 run (void *cls,
663      char *const *args,
664      const char *cfgfile,
665      const struct GNUNET_CONFIGURATION_Handle *cfg)
666 {
667   struct GNUNET_MQ_MessageHandler handlers[] =
668   { GNUNET_MQ_hd_var_size (data,
669                            GNUNET_MESSAGE_TYPE_CADET_CLI,
670                            struct GNUNET_MessageHeader,
671                            NULL),
672     GNUNET_MQ_handler_end () };
673
674   /* FIXME add option to monitor apps */
675   my_cfg = cfg;
676   target_id = args[0];
677   if (target_id && args[1])
678     target_port = args[1];
679
680   if (((0 != (request_peers | request_tunnels)) || (NULL != conn_id) ||
681        (NULL != channel_id) ) &&
682       (target_id != NULL) )
683   {
684     fprintf (stderr,
685              _ ("Extra arguments are not applicable "
686                 "in combination with this option.\n"));
687     return;
688   }
689
690   if (NULL != peer_id)
691   {
692     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
693     job = GNUNET_SCHEDULER_add_now (&show_peer, NULL);
694   }
695   else if (NULL != channel_id)
696   {
697     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
698     job = GNUNET_SCHEDULER_add_now (&show_channel, NULL);
699   }
700   else if (NULL != conn_id)
701   {
702     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
703     job = GNUNET_SCHEDULER_add_now (&show_connection, NULL);
704   }
705   else if (GNUNET_YES == request_peers)
706   {
707     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
708     job = GNUNET_SCHEDULER_add_now (&get_peers, NULL);
709   }
710   else if (GNUNET_YES == request_tunnels)
711   {
712     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
713     job = GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
714   }
715
716   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET service\n");
717   mh = GNUNET_CADET_connect (cfg);
718   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
719   if (NULL == mh)
720   {
721     GNUNET_SCHEDULER_shutdown ();
722     return;
723   }
724   if (NULL != listen_port)
725   {
726     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET listen port\n");
727     GNUNET_CRYPTO_hash (listen_port, strlen (listen_port), &porthash);
728     lp = GNUNET_CADET_open_port (mh,
729                                  &porthash,
730                                  &channel_incoming,
731                                  NULL,
732                                  NULL /* window changes */,
733                                  &channel_ended,
734                                  handlers);
735   }
736   if (NULL != target_id)
737   {
738     struct GNUNET_PeerIdentity pid;
739
740     if (GNUNET_OK !=
741         GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
742                                                     strlen (target_id),
743                                                     &pid.public_key))
744     {
745       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
746                   _ ("Invalid target `%s'\n"),
747                   target_id);
748       GNUNET_SCHEDULER_shutdown ();
749       return;
750     }
751     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
752                 "Connecting to `%s:%s'\n",
753                 target_id,
754                 target_port);
755     GNUNET_CRYPTO_hash (target_port, strlen (target_port), &porthash);
756     ch = GNUNET_CADET_channel_create (mh,
757                                       NULL,
758                                       &pid,
759                                       &porthash,
760                                       NULL /* window changes */,
761                                       &channel_ended,
762                                       handlers);
763     if (GNUNET_YES == echo)
764     {
765       echo_task = GNUNET_SCHEDULER_add_now (&send_echo, NULL);
766     }
767     else
768     {
769       listen_stdio ();
770     }
771   }
772
773   if ((NULL == lp) && (NULL == job) && (NULL == ch))
774   {
775     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, _ ("No action requested\n"));
776     GNUNET_SCHEDULER_shutdown ();
777     return;
778   }
779 }
780
781
782 /**
783  * The main function to obtain peer information.
784  *
785  * @param argc number of arguments from the command line
786  * @param argv command line arguments
787  * @return 0 ok, 1 on error
788  */
789 int
790 main (int argc, char *const *argv)
791 {
792   int res;
793   const char helpstr[] =
794     "Create tunnels and retrieve info about CADET's status.";
795   struct GNUNET_GETOPT_CommandLineOption options[] = {  /* I would use the terminology 'circuit' here...  --lynX */
796     GNUNET_GETOPT_option_string (
797       'C',
798       "connection",
799       "CONNECTION_ID",
800       gettext_noop ("Provide information about a particular connection"),
801       &conn_id),
802     GNUNET_GETOPT_option_flag ('e',
803                                "echo",
804                                gettext_noop ("Activate echo mode"),
805                                &echo),
806     GNUNET_GETOPT_option_string (
807       'o',
808       "open-port",
809       "SHARED_SECRET",
810       gettext_noop (
811         "Listen for connections using a shared secret among sender and recipient"),
812       &listen_port),
813     GNUNET_GETOPT_option_string ('p',
814                                  "peer",
815                                  "PEER_ID",
816                                  gettext_noop (
817                                    "Provide information about a patricular peer"),
818                                  &peer_id),
819     GNUNET_GETOPT_option_flag ('P',
820                                "peers",
821                                gettext_noop (
822                                  "Provide information about all peers"),
823                                &request_peers),
824     GNUNET_GETOPT_option_flag ('T',
825                                "tunnels",
826                                gettext_noop (
827                                  "Provide information about all tunnels"),
828                                &request_tunnels),
829     GNUNET_GETOPT_OPTION_END
830   };
831
832   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
833     return 2;
834
835   res = GNUNET_PROGRAM_run (argc,
836                             argv,
837                             "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
838                             gettext_noop (helpstr),
839                             options,
840                             &run,
841                             NULL);
842
843   GNUNET_free_nz ((void *) argv);
844
845   if (GNUNET_OK == res)
846     return 0;
847   return 1;
848 }
849
850
851 /* end of gnunet-cadet.c */