diff options
Diffstat (limited to 'src/cli/fs/gnunet-download.c')
-rw-r--r-- | src/cli/fs/gnunet-download.c | 385 |
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 | |||
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 | ¶llelism), | ||
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 */ | ||