tighten formatting rules
[oweals/gnunet.git] / src / ats-tool / gnunet-ats.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2009--2015 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 ats-tool/gnunet-ats.c
23  * @brief ATS command line tool
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_ats_service.h"
30 #include "gnunet_transport_service.h"
31
32 /**
33  * String to respresent unlimited
34  */
35 #define UNLIMITED_STRING "unlimited"
36
37
38 /**
39  * CLI Opt:
40  */
41 static int opt_resolve_addresses_numeric;
42
43 /**
44  * CLI Opt: Print verbose ATS information
45  */
46 static int opt_verbose;
47
48 /**
49  * CLI Option: List only addresses currently used (active)
50  */
51 static int opt_list_used;
52
53 /**
54  * CLI Option: List all addresses
55  */
56 static int opt_list_all;
57
58 /**
59  * CLI Option: set preference
60  */
61 static int opt_set_pref;
62
63 /**
64  * CLI Option: print quotas configured
65  */
66 static int opt_print_quotas;
67
68 /**
69  * CLI Option: Monitor addresses used
70  */
71 static int opt_monitor;
72
73 /**
74  * CLI Option: use specific peer
75  */
76 static char *opt_pid_str;
77
78 /**
79  * CLI Option: preference type to set
80  */
81 static char *opt_type_str;
82
83 /**
84  * CLI Option: preference value to set
85  */
86 static unsigned int opt_pref_value;
87
88 /**
89  * Final status code.
90  */
91 static int ret;
92
93 /**
94  * Number of results returned from service
95  */
96 static int stat_results;
97
98 /**
99  * State: all pending receive operations done?
100  */
101 static int stat_receive_done;
102
103 /**
104  * State: number of pending operations
105  */
106 static int stat_pending;
107
108 /**
109  * Which peer should we connect to?
110  */
111 static char *cpid_str;
112
113 /**
114  * ATS performance handle used
115  */
116 static struct GNUNET_ATS_PerformanceHandle *ph;
117
118 /**
119  * Our connectivity handle.
120  */
121 static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
122
123 /**
124  * Handle for address suggestion request.
125  */
126 static struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
127
128 /**
129  * ATS address list handle used
130  */
131 static struct GNUNET_ATS_AddressListHandle *alh;
132
133 /**
134  * Configuration handle
135  */
136 static struct GNUNET_CONFIGURATION_Handle *cfg;
137
138 /**
139  * Shutdown task
140  */
141 static struct GNUNET_SCHEDULER_Task *shutdown_task;
142
143 /**
144  * Hashmap to store addresses
145  */
146 static struct GNUNET_CONTAINER_MultiPeerMap *addresses;
147
148
149 /**
150  * Structure used to remember all pending address resolutions.
151  * We keep address information in here while we talk to transport
152  * to map the address to a string.
153  */
154 struct PendingResolutions
155 {
156   /**
157    * Kept in a DLL.
158    */
159   struct PendingResolutions *next;
160
161   /**
162    * Kept in a DLL.
163    */
164   struct PendingResolutions *prev;
165
166   /**
167    * Copy of the address we are resolving.
168    */
169   struct GNUNET_HELLO_Address *address;
170
171   /**
172    * Handle to the transport request to convert the address
173    * to a string.
174    */
175   struct GNUNET_TRANSPORT_AddressToStringContext *tats_ctx;
176
177   /**
178    * Performance data.
179    */
180   struct GNUNET_ATS_Properties properties;
181
182   /**
183    * Amount of outbound bandwidth assigned by ATS.
184    */
185   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
186
187   /**
188    * Amount of inbound bandwidth assigned by ATS.
189    */
190   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
191
192   /**
193    * Is this an active address?
194    */
195   int active;
196 };
197
198
199 /**
200  * Information we keep for an address.  Used to avoid
201  * printing the same data multiple times.
202  */
203 struct ATSAddress
204 {
205   /**
206    * Address information.
207    */
208   struct GNUNET_HELLO_Address *address;
209
210   /**
211    * Current outbound bandwidth.
212    */
213   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
214
215   /**
216    * Current inbound bandwidth.
217    */
218   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
219
220   /**
221    * Is this an active address?
222    */
223   int active;
224 };
225
226
227 /**
228  * Head of list of pending resolution requests.
229  */
230 static struct PendingResolutions *head;
231
232 /**
233  * Tail of list of pending resolution requests.
234  */
235 static struct PendingResolutions *tail;
236
237
238 /**
239  * Free address corresponding to a given peer.
240  *
241  * @param cls NULL
242  * @param key peer identity
243  * @param value the `struct ATSAddress *` to be freed
244  * @return #GNUNET_YES (always)
245  */
246 static int
247 free_addr_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
248 {
249   struct ATSAddress *a = value;
250
251   GNUNET_assert (GNUNET_OK ==
252                  GNUNET_CONTAINER_multipeermap_remove (addresses, key, value));
253   GNUNET_HELLO_address_free (a->address);
254   GNUNET_free (a);
255   return GNUNET_OK;
256 }
257
258
259 /**
260  * Task run on shutdown.
261  *
262  * @param cls NULL
263  */
264 static void
265 end (void *cls)
266 {
267   struct PendingResolutions *pr;
268   struct PendingResolutions *next;
269   unsigned int pending;
270
271   if (NULL != alh)
272   {
273     GNUNET_ATS_performance_list_addresses_cancel (alh);
274     alh = NULL;
275   }
276
277   if (NULL != ph)
278   {
279     GNUNET_ATS_performance_done (ph);
280     ph = NULL;
281   }
282
283   pending = 0;
284   next = head;
285   while (NULL != (pr = next))
286   {
287     next = pr->next;
288     GNUNET_CONTAINER_DLL_remove (head, tail, pr);
289     GNUNET_TRANSPORT_address_to_string_cancel (pr->tats_ctx);
290     GNUNET_free (pr->address);
291     GNUNET_free (pr);
292     pending++;
293   }
294   GNUNET_CONTAINER_multipeermap_iterate (addresses, &free_addr_it, NULL);
295   GNUNET_CONTAINER_multipeermap_destroy (addresses);
296   addresses = NULL;
297
298   if (0 < pending)
299     fprintf (stdout, _ ("%u address resolutions had a timeout\n"), pending);
300   if (opt_list_used || opt_list_all)
301     fprintf (stdout,
302              _ ("ATS returned stat_results for %u addresses\n"),
303              stat_results);
304
305   if (NULL != ats_sh)
306   {
307     GNUNET_ATS_connectivity_suggest_cancel (ats_sh);
308     ats_sh = NULL;
309   }
310   if (NULL != ats_ch)
311   {
312     GNUNET_ATS_connectivity_done (ats_ch);
313     ats_ch = NULL;
314   }
315   ret = 0;
316 }
317
318
319 /**
320  * Function to call with a textual representation of an address.  This
321  * function will be called several times with different possible
322  * textual representations, and a last time with @a address being NULL
323  * to signal the end of the iteration.  Note that @a address NULL
324  * always is the last call, regardless of the value in @a res.
325  *
326  * @param cls closure, a `struct PendingResolutions *`
327  * @param address NULL on end of iteration,
328  *        otherwise 0-terminated printable UTF-8 string,
329  *        in particular an empty string if @a res is #GNUNET_NO
330  * @param res result of the address to string conversion:
331  *        if #GNUNET_OK: conversion successful
332  *        if #GNUNET_NO: address was invalid (or not supported)
333  *        if #GNUNET_SYSERR: communication error (IPC error)
334  */
335 static void
336 transport_addr_to_str_cb (void *cls, const char *address, int res)
337 {
338   struct PendingResolutions *pr = cls;
339
340   if (NULL == address)
341   {
342     /* We're done */
343     GNUNET_CONTAINER_DLL_remove (head, tail, pr);
344     GNUNET_free (pr->address);
345     GNUNET_free (pr);
346     stat_pending--;
347
348     if ((GNUNET_YES == stat_receive_done) && (0 == stat_pending))
349     {
350       /* All messages received and no resolutions pending*/
351       if (shutdown_task != NULL)
352         GNUNET_SCHEDULER_cancel (shutdown_task);
353       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
354     }
355     return;
356   }
357   switch (res)
358   {
359   case GNUNET_SYSERR:
360     fprintf (
361       stderr,
362       "Failed to convert address for peer `%s' plugin `%s' length %u to string (communication error)\n",
363       GNUNET_i2s (&pr->address->peer),
364       pr->address->transport_name,
365       (unsigned int) pr->address->address_length);
366     return;
367
368   case GNUNET_NO:
369     fprintf (
370       stderr,
371       "Failed to convert address for peer `%s' plugin `%s' length %u to string (address invalid or not supported)\n",
372       GNUNET_i2s (&pr->address->peer),
373       pr->address->transport_name,
374       (unsigned int) pr->address->address_length);
375     return;
376
377   case GNUNET_OK:
378     /* continues below */
379     break;
380
381   default:
382     GNUNET_break (0);
383     return;
384   }
385
386   fprintf (
387     stdout,
388     _ (
389       "Peer `%s' plugin `%s', address `%s', `%s' bw out: %u Bytes/s, bw in %u Bytes/s, %s\n"),
390     GNUNET_i2s (&pr->address->peer),
391     pr->address->transport_name,
392     address,
393     GNUNET_NT_to_string (pr->properties.scope),
394     ntohl (pr->bandwidth_out.value__),
395     ntohl (pr->bandwidth_in.value__),
396     pr->active ? _ ("active ") : _ ("inactive "));
397 }
398
399
400 /**
401  * Closure for #find_address_it().
402  */
403 struct AddressFindCtx
404 {
405   /**
406    * Address we are looking for.
407    */
408   const struct GNUNET_HELLO_Address *src;
409
410   /**
411    * Where to write the `struct ATSAddress` if we found one that matches.
412    */
413   struct ATSAddress *res;
414 };
415
416
417 /**
418  * Find address corresponding to a given peer.
419  *
420  * @param cls the `struct AddressFindCtx *`
421  * @param key peer identity
422  * @param value the `struct ATSAddress *` for an existing address
423  * @return #GNUNET_NO if we found a match, #GNUNET_YES if not
424  */
425 static int
426 find_address_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
427 {
428   struct AddressFindCtx *actx = cls;
429   struct ATSAddress *exist = value;
430
431   if (0 == GNUNET_HELLO_address_cmp (actx->src, exist->address))
432   {
433     actx->res = exist;
434     return GNUNET_NO;
435   }
436   return GNUNET_YES;
437 }
438
439
440 /**
441  * Signature of a function that is called with QoS information about an address.
442  *
443  * @param cls closure (NULL)
444  * @param address the address, NULL if ATS service was disconnected
445  * @param active #GNUNET_YES if this address is actively used
446  *        to maintain a connection to a peer;
447  *        #GNUNET_NO if the address is not actively used;
448  *        #GNUNET_SYSERR if this address is no longer available for ATS
449  * @param bandwidth_out assigned outbound bandwidth for the connection
450  * @param bandwidth_in assigned inbound bandwidth for the connection
451  * @param prop performance data for the address (as far as known)
452  */
453 static void
454 ats_perf_mon_cb (void *cls,
455                  const struct GNUNET_HELLO_Address *address,
456                  int active,
457                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
458                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
459                  const struct GNUNET_ATS_Properties *prop)
460 {
461   struct PendingResolutions *pr;
462   struct PendingResolutions *cur;
463   struct PendingResolutions *next;
464
465   if (NULL == address)
466   {
467     /* ATS service temporarily disconnected, remove current state */
468     next = head;
469     for (cur = next; NULL != cur; cur = next)
470     {
471       next = cur->next;
472       GNUNET_CONTAINER_DLL_remove (head, tail, cur);
473       GNUNET_TRANSPORT_address_to_string_cancel (cur->tats_ctx);
474       GNUNET_HELLO_address_free (cur->address);
475       GNUNET_free (cur);
476     }
477     GNUNET_CONTAINER_multipeermap_iterate (addresses, &free_addr_it, NULL);
478     return;
479   }
480   if (GNUNET_SYSERR == active)
481   {
482     /* remove address */
483     struct AddressFindCtx actx;
484
485     actx.src = address;
486     actx.res = NULL;
487     GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
488                                                 &address->peer,
489                                                 &find_address_it,
490                                                 &actx);
491     if (NULL == actx.res)
492     {
493       GNUNET_break (0);
494       return;
495     }
496     GNUNET_break (GNUNET_OK ==
497                   GNUNET_CONTAINER_multipeermap_remove (addresses,
498                                                         &address->peer,
499                                                         actx.res));
500     fprintf (stdout,
501              _ ("Removed address of peer `%s' with plugin `%s'\n"),
502              GNUNET_i2s (&address->peer),
503              actx.res->address->transport_name);
504     GNUNET_HELLO_address_free (actx.res);
505     return;
506   }
507
508   if (GNUNET_NO == opt_verbose)
509   {
510     struct AddressFindCtx actx;
511     struct ATSAddress *a;
512
513     actx.src = address;
514     actx.res = NULL;
515     GNUNET_CONTAINER_multipeermap_get_multiple (addresses,
516                                                 &address->peer,
517                                                 &find_address_it,
518                                                 &actx);
519     if ((NULL != actx.res))
520     {
521       if ((bandwidth_in.value__ == actx.res->bandwidth_in.value__) &&
522           (bandwidth_out.value__ == actx.res->bandwidth_out.value__) &&
523           (active == actx.res->active))
524       {
525         return;       /* Nothing to do here */
526       }
527       else
528       {
529         actx.res->bandwidth_in = bandwidth_in;
530         actx.res->bandwidth_out = bandwidth_out;
531       }
532     }
533     else
534     {
535       a = GNUNET_new (struct ATSAddress);
536
537       a->address = GNUNET_HELLO_address_copy (address);
538       a->bandwidth_in = bandwidth_in;
539       a->bandwidth_out = bandwidth_out;
540       a->active = active;
541       GNUNET_CONTAINER_multipeermap_put (
542         addresses,
543         &address->peer,
544         a,
545         GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
546     }
547   }
548
549   pr = GNUNET_new (struct PendingResolutions);
550   pr->properties = *prop;
551   pr->address = GNUNET_HELLO_address_copy (address);
552   pr->bandwidth_in = bandwidth_in;
553   pr->bandwidth_out = bandwidth_out;
554   pr->active = active;
555   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (
556     cfg,
557     address,
558     opt_resolve_addresses_numeric,
559     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
560     &transport_addr_to_str_cb,
561     pr);
562   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
563   stat_results++;
564   stat_pending++;
565 }
566
567
568 /**
569  * Signature of a function that is called with QoS information about an address.
570  *
571  * @param cls closure (NULL)
572  * @param address the address, NULL if ATS service was disconnected
573  * @param active is this address actively used to maintain a connection
574           to a peer
575  * @param bandwidth_out assigned outbound bandwidth for the connection
576  * @param bandwidth_in assigned inbound bandwidth for the connection
577  * @param prop performance data for the address (as far as known)
578  */
579 static void
580 ats_perf_cb (void *cls,
581              const struct GNUNET_HELLO_Address *address,
582              int active,
583              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
584              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
585              const struct GNUNET_ATS_Properties *prop)
586 {
587   struct PendingResolutions *pr;
588
589   if (NULL == address)
590   {
591     /* All messages received */
592     stat_receive_done = GNUNET_YES;
593     alh = NULL;
594     if (0 == stat_pending)
595     {
596       /* All messages received and no resolutions pending*/
597       if (shutdown_task != NULL)
598         GNUNET_SCHEDULER_cancel (shutdown_task);
599       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
600     }
601     return;
602   }
603
604   pr = GNUNET_new (struct PendingResolutions);
605   pr->properties = *prop;
606   pr->address = GNUNET_HELLO_address_copy (address);
607   pr->bandwidth_in = bandwidth_in;
608   pr->bandwidth_out = bandwidth_out;
609   pr->active = active;
610   pr->tats_ctx = GNUNET_TRANSPORT_address_to_string (
611     cfg,
612     address,
613     opt_resolve_addresses_numeric,
614     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
615     &transport_addr_to_str_cb,
616     pr);
617   GNUNET_CONTAINER_DLL_insert (head, tail, pr);
618   stat_results++;
619   stat_pending++;
620 }
621
622
623 /**
624  * Print information about the quotas configured for the various
625  * network scopes.
626  *
627  * @param cfg configuration to obtain quota information from
628  * @return total number of ATS network types known
629  */
630 static unsigned int
631 print_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg)
632 {
633   char *entry_in = NULL;
634   char *entry_out = NULL;
635   char *quota_out_str;
636   char *quota_in_str;
637   unsigned long long int quota_out;
638   unsigned long long int quota_in;
639   int c;
640
641   for (c = 0; (c < GNUNET_NT_COUNT); c++)
642   {
643     GNUNET_asprintf (&entry_out, "%s_QUOTA_OUT", GNUNET_NT_to_string (c));
644     GNUNET_asprintf (&entry_in, "%s_QUOTA_IN", GNUNET_NT_to_string (c));
645
646     /* quota out */
647     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
648                                                             "ats",
649                                                             entry_out,
650                                                             &quota_out_str))
651     {
652       if ((0 == strcmp (quota_out_str, UNLIMITED_STRING)) ||
653           (GNUNET_SYSERR ==
654            GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &quota_out)))
655         quota_out = UINT32_MAX;
656
657       GNUNET_free (quota_out_str);
658       GNUNET_asprintf (&quota_out_str, "%llu", quota_out);
659     }
660     else
661     {
662       fprintf (stderr,
663                "Outbound quota for network `%11s' not configured!\n",
664                GNUNET_NT_to_string (c));
665       GNUNET_asprintf (&quota_out_str, "-");
666     }
667     GNUNET_free (entry_out);
668
669     /* quota in */
670     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
671                                                             "ats",
672                                                             entry_in,
673                                                             &quota_in_str))
674     {
675       if ((0 == strcmp (quota_in_str, UNLIMITED_STRING)) ||
676           (GNUNET_SYSERR ==
677            GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
678         quota_in = UINT32_MAX;
679       GNUNET_free (quota_in_str);
680       GNUNET_asprintf (&quota_in_str, "%llu", quota_in);
681     }
682     else
683     {
684       fprintf (stderr,
685                "Inbound quota for network `%11s' not configured!\n",
686                GNUNET_NT_to_string (c));
687       GNUNET_asprintf (&quota_in_str, "-");
688     }
689     GNUNET_free (entry_in);
690
691     fprintf (stdout,
692              _ ("Quota for network `%11s' (in/out): %10s / %10s\n"),
693              GNUNET_NT_to_string (c),
694              quota_in_str,
695              quota_out_str);
696     GNUNET_free (quota_out_str);
697     GNUNET_free (quota_in_str);
698   }
699   return GNUNET_NT_COUNT;
700 }
701
702
703 /**
704  * Main function that will be run by the scheduler.
705  *
706  * @param cls closure
707  * @param args remaining command-line arguments
708  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
709  * @param my_cfg configuration
710  */
711 static void
712 run (void *cls,
713      char *const *args,
714      const char *cfgfile,
715      const struct GNUNET_CONFIGURATION_Handle *my_cfg)
716 {
717   struct GNUNET_PeerIdentity pid;
718   struct GNUNET_PeerIdentity cpid;
719   unsigned int c;
720   unsigned int type;
721
722   cfg = (struct GNUNET_CONFIGURATION_Handle *) my_cfg;
723   addresses = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
724   stat_results = 0;
725
726   c = 0;
727   if (NULL != opt_pid_str)
728   {
729     if (GNUNET_OK !=
730         GNUNET_CRYPTO_eddsa_public_key_from_string (opt_pid_str,
731                                                     strlen (opt_pid_str),
732                                                     &pid.public_key))
733     {
734       fprintf (stderr, _ ("Failed to parse peer identity `%s'\n"), opt_pid_str);
735       return;
736     }
737   }
738   if (NULL != cpid_str)
739   {
740     if (GNUNET_OK !=
741         GNUNET_CRYPTO_eddsa_public_key_from_string (cpid_str,
742                                                     strlen (cpid_str),
743                                                     &cpid.public_key))
744     {
745       fprintf (stderr, _ ("Failed to parse peer identity `%s'\n"), cpid_str);
746       return;
747     }
748     c++;
749   }
750
751   c += opt_list_all + opt_list_used + opt_monitor + opt_set_pref;
752
753   if (1 < c)
754   {
755     fprintf (stderr,
756              _ ("Please select one operation: %s or %s or %s or %s or %s\n"),
757              "--used",
758              "--all",
759              "--monitor",
760              "--preference",
761              "--quotas");
762     return;
763   }
764   if (0 == c)
765     opt_list_used = GNUNET_YES; /* set default */
766   if (opt_print_quotas)
767   {
768     ret = print_quotas (cfg);
769     return;
770   }
771   if (opt_list_all)
772   {
773     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
774     if (NULL == ph)
775     {
776       fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
777       return;
778     }
779     alh = GNUNET_ATS_performance_list_addresses (ph,
780                                                  (NULL == opt_pid_str) ? NULL
781                                                  : &pid,
782                                                  GNUNET_YES,
783                                                  &ats_perf_cb,
784                                                  NULL);
785     if (NULL == alh)
786     {
787       fprintf (stderr,
788                "%s",
789                _ ("Cannot issue request to ATS service, exiting...\n"));
790       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
791       return;
792     }
793     shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end, NULL);
794     return;
795   }
796   if (opt_list_used)
797   {
798     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
799     if (NULL == ph)
800       fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
801
802     alh = GNUNET_ATS_performance_list_addresses (ph,
803                                                  (NULL == opt_pid_str) ? NULL
804                                                  : &pid,
805                                                  GNUNET_NO,
806                                                  &ats_perf_cb,
807                                                  NULL);
808     if (NULL == alh)
809     {
810       fprintf (stderr,
811                "%s",
812                _ ("Cannot issue request to ATS service, exiting...\n"));
813       shutdown_task = GNUNET_SCHEDULER_add_now (&end, NULL);
814       return;
815     }
816     shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end, NULL);
817     return;
818   }
819   if (opt_monitor)
820   {
821     ph = GNUNET_ATS_performance_init (cfg, &ats_perf_mon_cb, NULL);
822     shutdown_task = GNUNET_SCHEDULER_add_shutdown (&end, NULL);
823     if (NULL == ph)
824     {
825       fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
826       GNUNET_SCHEDULER_shutdown ();
827     }
828     return;
829   }
830   if (opt_set_pref)
831   {
832     if (NULL == opt_type_str)
833     {
834       fprintf (stderr, "%s", _ ("No preference type given!\n"));
835       return;
836     }
837     if (NULL == opt_pid_str)
838     {
839       fprintf (stderr, "%s", _ ("No peer given!\n"));
840       return;
841     }
842
843     for (c = 0; c < strlen (opt_type_str); c++)
844     {
845       if (isupper ((unsigned char) opt_type_str[c]))
846         opt_type_str[c] = tolower ((unsigned char) opt_type_str[c]);
847     }
848
849     if (0 == strcasecmp ("latency", opt_type_str))
850       type = GNUNET_ATS_PREFERENCE_LATENCY;
851     else if (0 == strcasecmp ("bandwidth", opt_type_str))
852       type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
853     else
854     {
855       fprintf (stderr, "%s", _ ("Valid type required\n"));
856       return;
857     }
858
859     /* set */
860     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
861     if (NULL == ph)
862       fprintf (stderr, "%s", _ ("Cannot connect to ATS service, exiting...\n"));
863
864     GNUNET_ATS_performance_change_preference (ph,
865                                               &pid,
866                                               type,
867                                               (double) opt_pref_value,
868                                               GNUNET_ATS_PREFERENCE_END);
869
870     shutdown_task =
871       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &end, NULL);
872     return;
873   }
874   if (NULL != cpid_str)
875   {
876     ats_ch = GNUNET_ATS_connectivity_init (cfg);
877     ats_sh = GNUNET_ATS_connectivity_suggest (ats_ch, &cpid, 1000);
878     shutdown_task =
879       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &end, NULL);
880     return;
881   }
882   ret = 1;
883 }
884
885
886 /**
887  * The main function.
888  *
889  * @param argc number of arguments from the command line
890  * @param argv command line arguments
891  * @return 0 ok, 1 on error
892  */
893 int
894 main (int argc, char *const *argv)
895 {
896   int res;
897
898   opt_resolve_addresses_numeric = GNUNET_NO;
899   opt_monitor = GNUNET_NO;
900   opt_list_all = GNUNET_NO;
901   opt_list_used = GNUNET_NO;
902   opt_set_pref = GNUNET_NO;
903   stat_pending = 0;
904   stat_receive_done = GNUNET_NO;
905   opt_type_str = NULL;
906
907   struct GNUNET_GETOPT_CommandLineOption options[] =
908   { GNUNET_GETOPT_option_flag ('u',
909                                "used",
910                                gettext_noop (
911                                  "get list of active addresses currently used"),
912                                &opt_list_used),
913     GNUNET_GETOPT_option_flag ('a',
914                                "all",
915                                gettext_noop (
916                                  "get list of all active addresses"),
917                                &opt_list_all),
918
919     GNUNET_GETOPT_option_string ('C',
920                                  "connect",
921                                  NULL,
922                                  gettext_noop ("connect to PEER"),
923                                  &cpid_str),
924     GNUNET_GETOPT_option_flag ('n',
925                                "numeric",
926                                gettext_noop (
927                                  "do not resolve IP addresses to hostnames"),
928                                &opt_resolve_addresses_numeric),
929
930     GNUNET_GETOPT_option_flag ('m',
931                                "monitor",
932                                gettext_noop ("monitor mode"),
933                                &opt_monitor),
934
935     GNUNET_GETOPT_option_flag ('p',
936                                "preference",
937                                gettext_noop (
938                                  "set preference for the given peer"),
939                                &opt_set_pref),
940
941     GNUNET_GETOPT_option_flag ('q',
942                                "quotas",
943                                gettext_noop ("print all configured quotas"),
944                                &opt_print_quotas),
945     GNUNET_GETOPT_option_string ('i',
946                                  "id",
947                                  "TYPE",
948                                  gettext_noop ("peer id"),
949                                  &opt_pid_str),
950
951     GNUNET_GETOPT_option_string ('t',
952                                  "type",
953                                  "TYPE",
954                                  gettext_noop (
955                                    "preference type to set: latency | bandwidth"),
956                                  &opt_type_str),
957
958     GNUNET_GETOPT_option_uint ('k',
959                                "value",
960                                "VALUE",
961                                gettext_noop ("preference value"),
962                                &opt_pref_value),
963
964     GNUNET_GETOPT_option_flag (
965       'V',
966       "verbose",
967       gettext_noop ("verbose output (include ATS address properties)"),
968       &opt_verbose),
969     GNUNET_GETOPT_OPTION_END };
970
971   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
972     return 2;
973
974   res = GNUNET_PROGRAM_run (argc,
975                             argv,
976                             "gnunet-ats",
977                             gettext_noop ("Print information about ATS state"),
978                             options,
979                             &run,
980                             NULL);
981   GNUNET_free_non_null (opt_pid_str);
982   GNUNET_free_non_null (opt_type_str);
983   GNUNET_free ((void *) argv);
984
985   if (GNUNET_OK == res)
986     return ret;
987   else
988     return 1;
989 }
990
991
992 /* end of gnunet-ats.c */