gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

gnunet-download.c (10747B)


      1 /*
      2      This file is part of GNUnet.
      3      Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 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  * @file fs/gnunet-download.c
     22  * @brief downloading for files on GNUnet
     23  * @author Christian Grothoff
     24  * @author Krista Bennett
     25  * @author James Blackwell
     26  * @author Igor Wronsky
     27  */
     28 #include "platform.h"
     29 
     30 #include "gnunet_fs_service.h"
     31 
     32 static int ret;
     33 
     34 static unsigned int verbose;
     35 
     36 static int delete_incomplete;
     37 
     38 static const struct GNUNET_CONFIGURATION_Handle *cfg;
     39 
     40 static struct GNUNET_FS_Handle *ctx;
     41 
     42 static struct GNUNET_FS_DownloadContext *dc;
     43 
     44 static unsigned int anonymity = 1;
     45 
     46 static unsigned int parallelism = 16;
     47 
     48 static unsigned int request_parallelism = 4092;
     49 
     50 static int do_recursive;
     51 
     52 static char *filename;
     53 
     54 static int local_only;
     55 
     56 
     57 static void
     58 cleanup_task (void *cls)
     59 {
     60   GNUNET_FS_stop (ctx);
     61   ctx = NULL;
     62 }
     63 
     64 
     65 static void
     66 shutdown_task (void *cls)
     67 {
     68   if (NULL != dc)
     69   {
     70     GNUNET_FS_download_stop (dc, delete_incomplete);
     71     dc = NULL;
     72   }
     73 }
     74 
     75 
     76 /**
     77  * Display progress bar (if tty).
     78  *
     79  * @param x current position in the download
     80  * @param n total size of the download
     81  * @param w desired number of steps in the progress bar
     82  */
     83 static void
     84 display_bar (unsigned long long x, unsigned long long n, unsigned int w)
     85 {
     86   char buf[w + 20];
     87   unsigned int p;
     88   unsigned int endeq;
     89   float ratio_complete;
     90 
     91   if (0 == isatty (1))
     92     return;
     93   ratio_complete = x / (float) n;
     94   endeq = ratio_complete * w;
     95   GNUNET_snprintf (buf, sizeof(buf), "%3d%% [", (int) (ratio_complete * 100));
     96   for (p = 0; p < endeq; p++)
     97     strcat (buf, "=");
     98   for (p = endeq; p < w; p++)
     99     strcat (buf, " ");
    100   strcat (buf, "]\r");
    101   printf ("%s", buf);
    102   fflush (stdout);
    103 }
    104 
    105 
    106 /**
    107  * Called by FS client to give information about the progress of an
    108  * operation.
    109  *
    110  * @param cls closure
    111  * @param info details about the event, specifying the event type
    112  *        and various bits about the event
    113  * @return client-context (for the next progress call
    114  *         for this operation; should be set to NULL for
    115  *         SUSPEND and STOPPED events).  The value returned
    116  *         will be passed to future callbacks in the respective
    117  *         field in the `struct GNUNET_FS_ProgressInfo`
    118  */
    119 static void *
    120 progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
    121 {
    122   char *s;
    123   const char *s2;
    124   char *t;
    125 
    126   switch (info->status)
    127   {
    128   case GNUNET_FS_STATUS_DOWNLOAD_START:
    129     if (verbose > 1)
    130       fprintf (stderr,
    131                _ ("Starting download `%s'.\n"),
    132                info->value.download.filename);
    133     break;
    134 
    135   case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
    136     if (verbose)
    137     {
    138       s = GNUNET_strdup (
    139         GNUNET_STRINGS_relative_time_to_string (info->value.download.eta,
    140                                                 GNUNET_YES));
    141       if (info->value.download.specifics.progress.block_download_duration
    142           .rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
    143         s2 = _ ("<unknown time>");
    144       else
    145         s2 = GNUNET_STRINGS_relative_time_to_string (info->value.download
    146                                                      .specifics.progress
    147                                                      .block_download_duration,
    148                                                      GNUNET_YES);
    149       t = GNUNET_STRINGS_byte_size_fancy (
    150         info->value.download.completed * 1000LL
    151         / (info->value.download.duration.rel_value_us + 1));
    152       fprintf (
    153         stdout,
    154         _ (
    155           "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"),
    156         info->value.download.filename,
    157         (unsigned long long) info->value.download.completed,
    158         (unsigned long long) info->value.download.size,
    159         s,
    160         t,
    161         s2);
    162       GNUNET_free (s);
    163       GNUNET_free (t);
    164     }
    165     else
    166     {
    167       display_bar (info->value.download.completed,
    168                    info->value.download.size,
    169                    60);
    170     }
    171     break;
    172 
    173   case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
    174     if (0 != isatty (1))
    175       fprintf (stdout, "\n");
    176     fprintf (stderr,
    177              _ ("Error downloading: %s.\n"),
    178              info->value.download.specifics.error.message);
    179     GNUNET_SCHEDULER_shutdown ();
    180     break;
    181 
    182   case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
    183     s = GNUNET_STRINGS_byte_size_fancy (
    184       info->value.download.completed * 1000
    185       / (info->value.download.duration.rel_value_us + 1));
    186     if (0 != isatty (1))
    187       fprintf (stdout, "\n");
    188     fprintf (stdout,
    189              _ ("Downloading `%s' done (%s/s).\n"),
    190              info->value.download.filename,
    191              s);
    192     GNUNET_free (s);
    193     if (info->value.download.dc == dc)
    194       GNUNET_SCHEDULER_shutdown ();
    195     break;
    196 
    197   case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
    198     if (info->value.download.dc == dc)
    199       GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
    200     break;
    201 
    202   case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
    203   case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
    204     break;
    205 
    206   default:
    207     fprintf (stderr, _ ("Unexpected status: %d\n"), info->status);
    208     break;
    209   }
    210   return NULL;
    211 }
    212 
    213 
    214 /**
    215  * Main function that will be run by the scheduler.
    216  *
    217  * @param cls closure
    218  * @param args remaining command-line arguments
    219  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
    220  * @param c configuration
    221  */
    222 static void
    223 run (void *cls,
    224      char *const *args,
    225      const char *cfgfile,
    226      const struct GNUNET_CONFIGURATION_Handle *c)
    227 {
    228   struct GNUNET_FS_Uri *uri;
    229   char *emsg;
    230   enum GNUNET_FS_DownloadOptions options;
    231 
    232   if (NULL == args[0])
    233   {
    234     fprintf (stderr, "%s", _ ("You need to specify a URI argument.\n"));
    235     return;
    236   }
    237   uri = GNUNET_FS_uri_parse (args[0], &emsg);
    238   if (NULL == uri)
    239   {
    240     fprintf (stderr, _ ("Failed to parse URI: %s\n"), emsg);
    241     GNUNET_free (emsg);
    242     ret = 1;
    243     return;
    244   }
    245   if ((! GNUNET_FS_uri_test_chk (uri)) && (! GNUNET_FS_uri_test_loc (uri)))
    246   {
    247     fprintf (stderr, "%s", _ ("Only CHK or LOC URIs supported.\n"));
    248     ret = 1;
    249     GNUNET_FS_uri_destroy (uri);
    250     return;
    251   }
    252   if (NULL == filename)
    253   {
    254     fprintf (stderr, "%s", _ ("Target filename must be specified.\n"));
    255     ret = 1;
    256     GNUNET_FS_uri_destroy (uri);
    257     return;
    258   }
    259   cfg = c;
    260   ctx = GNUNET_FS_start (cfg,
    261                          "gnunet-download",
    262                          &progress_cb,
    263                          NULL,
    264                          GNUNET_FS_FLAGS_NONE,
    265                          GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM,
    266                          parallelism,
    267                          GNUNET_FS_OPTIONS_REQUEST_PARALLELISM,
    268                          request_parallelism,
    269                          GNUNET_FS_OPTIONS_END);
    270   if (NULL == ctx)
    271   {
    272     fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS");
    273     GNUNET_FS_uri_destroy (uri);
    274     ret = 1;
    275     return;
    276   }
    277   options = GNUNET_FS_DOWNLOAD_OPTION_NONE;
    278   if (do_recursive)
    279     options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
    280   if (local_only)
    281     options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY;
    282   dc = GNUNET_FS_download_start (ctx,
    283                                  uri,
    284                                  NULL,
    285                                  filename,
    286                                  NULL,
    287                                  0,
    288                                  GNUNET_FS_uri_chk_get_file_size (uri),
    289                                  anonymity,
    290                                  options,
    291                                  NULL,
    292                                  NULL);
    293   GNUNET_FS_uri_destroy (uri);
    294   if (dc == NULL)
    295   {
    296     GNUNET_FS_stop (ctx);
    297     ctx = NULL;
    298     return;
    299   }
    300   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
    301 }
    302 
    303 
    304 /**
    305  * The main function to download GNUnet.
    306  *
    307  * @param argc number of arguments from the command line
    308  * @param argv command line arguments
    309  * @return 0 ok, 1 on error
    310  */
    311 int
    312 main (int argc, char *const *argv)
    313 {
    314   struct GNUNET_GETOPT_CommandLineOption options[] =
    315   { GNUNET_GETOPT_option_uint ('a',
    316                                "anonymity",
    317                                "LEVEL",
    318                                gettext_noop (
    319                                  "set the desired LEVEL of receiver-anonymity"),
    320                                &anonymity),
    321 
    322     GNUNET_GETOPT_option_flag (
    323       'D',
    324       "delete-incomplete",
    325       gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"),
    326       &delete_incomplete),
    327 
    328     GNUNET_GETOPT_option_flag (
    329       'n',
    330       "no-network",
    331       gettext_noop ("only search the local peer (no P2P network search)"),
    332       &local_only),
    333     GNUNET_GETOPT_option_string ('o',
    334                                  "output",
    335                                  "FILENAME",
    336                                  gettext_noop ("write the file to FILENAME"),
    337                                  &filename),
    338     GNUNET_GETOPT_option_uint (
    339       'p',
    340       "parallelism",
    341       "DOWNLOADS",
    342       gettext_noop (
    343         "set the maximum number of parallel downloads that is allowed"),
    344       &parallelism),
    345     GNUNET_GETOPT_option_uint (
    346       'r',
    347       "request-parallelism",
    348       "REQUESTS",
    349       gettext_noop (
    350         "set the maximum number of parallel requests for blocks that is allowed"),
    351       &request_parallelism),
    352     GNUNET_GETOPT_option_flag ('R',
    353                                "recursive",
    354                                gettext_noop (
    355                                  "download a GNUnet directory recursively"),
    356                                &do_recursive),
    357     GNUNET_GETOPT_option_increment_uint (
    358       'V',
    359       "verbose",
    360       gettext_noop ("be verbose (print progress information)"),
    361       &verbose),
    362     GNUNET_GETOPT_OPTION_END };
    363 
    364   ret =
    365     (GNUNET_OK ==
    366      GNUNET_PROGRAM_run (
    367        GNUNET_OS_project_data_gnunet (),
    368        argc,
    369        argv,
    370        "gnunet-download [OPTIONS] URI",
    371        gettext_noop (
    372          "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/chk/...)"),
    373        options,
    374        &run,
    375        NULL))
    376     ? ret
    377     : 1;
    378   return ret;
    379 }
    380 
    381 
    382 /* end of gnunet-download.c */