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