diff options
Diffstat (limited to 'src/cli/cadet/gnunet-cadet.c')
-rw-r--r-- | src/cli/cadet/gnunet-cadet.c | 851 |
1 files changed, 851 insertions, 0 deletions
diff --git a/src/cli/cadet/gnunet-cadet.c b/src/cli/cadet/gnunet-cadet.c new file mode 100644 index 000000000..c77fb914c --- /dev/null +++ b/src/cli/cadet/gnunet-cadet.c | |||
@@ -0,0 +1,851 @@ | |||
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 "../../service/cadet/cadet.h" // FIXME Smell: this should not be shared like this. | ||
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 */ | ||