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