aboutsummaryrefslogtreecommitdiff
path: root/src/cli/fs/gnunet-download.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/fs/gnunet-download.c')
-rw-r--r--src/cli/fs/gnunet-download.c385
1 files changed, 385 insertions, 0 deletions
diff --git a/src/cli/fs/gnunet-download.c b/src/cli/fs/gnunet-download.c
new file mode 100644
index 000000000..4694077e9
--- /dev/null
+++ b/src/cli/fs/gnunet-download.c
@@ -0,0 +1,385 @@
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
32static int ret;
33
34static unsigned int verbose;
35
36static int delete_incomplete;
37
38static const struct GNUNET_CONFIGURATION_Handle *cfg;
39
40static struct GNUNET_FS_Handle *ctx;
41
42static struct GNUNET_FS_DownloadContext *dc;
43
44static unsigned int anonymity = 1;
45
46static unsigned int parallelism = 16;
47
48static unsigned int request_parallelism = 4092;
49
50static int do_recursive;
51
52static char *filename;
53
54static int local_only;
55
56
57static void
58cleanup_task (void *cls)
59{
60 GNUNET_FS_stop (ctx);
61 ctx = NULL;
62}
63
64
65static void
66shutdown_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 */
83static void
84display_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 */
119static void *
120progress_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 */
222static void
223run (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 */
311int
312main (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 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
365 return 2;
366
367 ret =
368 (GNUNET_OK ==
369 GNUNET_PROGRAM_run (
370 argc,
371 argv,
372 "gnunet-download [OPTIONS] URI",
373 gettext_noop (
374 "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/chk/...)"),
375 options,
376 &run,
377 NULL))
378 ? ret
379 : 1;
380 GNUNET_free_nz ((void *) argv);
381 return ret;
382}
383
384
385/* end of gnunet-download.c */