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