aboutsummaryrefslogtreecommitdiff
path: root/src/cadet/gnunet-cadet.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cadet/gnunet-cadet.c')
-rw-r--r--src/cadet/gnunet-cadet.c851
1 files changed, 0 insertions, 851 deletions
diff --git a/src/cadet/gnunet-cadet.c b/src/cadet/gnunet-cadet.c
deleted file mode 100644
index 9b7538ae7..000000000
--- a/src/cadet/gnunet-cadet.c
+++ /dev/null
@@ -1,851 +0,0 @@
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 */
37static int request_peers;
38
39/**
40 * Option --peer
41 */
42static char *peer_id;
43
44/**
45 * Option -T.
46 */
47static int request_tunnels;
48
49/**
50 * Option --connection
51 */
52static char *conn_id;
53
54/**
55 * Option --channel
56 */
57static char *channel_id;
58
59/**
60 * Port to listen on (-o).
61 */
62static char *listen_port;
63
64/**
65 * Request echo service
66 */
67static int echo;
68
69/**
70 * Time of last echo request.
71 */
72static struct GNUNET_TIME_Absolute echo_time;
73
74/**
75 * Task for next echo request.
76 */
77static struct GNUNET_SCHEDULER_Task *echo_task;
78
79/**
80 * Peer to connect to.
81 */
82static char *target_id;
83
84/**
85 * Port to connect to
86 */
87static char *target_port = "default";
88
89/**
90 * Cadet handle.
91 */
92static struct GNUNET_CADET_Handle *mh;
93
94/**
95 * Our configuration.
96 */
97static const struct GNUNET_CONFIGURATION_Handle *my_cfg;
98
99/**
100 * Active get path operation.
101 */
102static struct GNUNET_CADET_GetPath *gpo;
103
104/**
105 * Active peer listing operation.
106 */
107static struct GNUNET_CADET_PeersLister *plo;
108
109/**
110 * Active tunnel listing operation.
111 */
112static struct GNUNET_CADET_ListTunnels *tio;
113
114/**
115 * Channel handle.
116 */
117static struct GNUNET_CADET_Channel *ch;
118
119/**
120 * HashCode of the given port string
121 */
122static struct GNUNET_HashCode porthash;
123
124/**
125 * Data structure for ongoing reception of incoming virtual circuits.
126 */
127struct GNUNET_CADET_Port *lp;
128
129/**
130 * Task for reading from stdin.
131 */
132static struct GNUNET_SCHEDULER_Task *rd_task;
133
134/**
135 * Task for main job.
136 */
137static struct GNUNET_SCHEDULER_Task *job;
138
139static unsigned int sent_pkt;
140
141
142/**
143 * Wait for input on STDIO and send it out over the #ch.
144 */
145static void
146listen_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 */
156static const char *
157enc_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 */
186static const char *
187conn_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 */
217static void
218shutdown_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
269void
270mq_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 */
281static void
282read_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 */
331static void
332listen_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 */
358static void
359channel_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 */
382static void *
383channel_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 */
406static void
407send_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 */
428static int
429check_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 */
445static void
446handle_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 */
511static void
512peers_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 */
535static void
536path_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 */
559static void
560tunnels_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 */
583static void
584get_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 */
596static void
597show_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 */
619static void
620get_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 */
632static void
633show_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 */
645static void
646show_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 */
661static void
662run (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 */
789int
790main (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 */