diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-06-17 21:29:30 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-06-17 21:29:30 +0000 |
commit | 2b7808e952a77f2cb951d81f3308a9fbaf4e56ec (patch) | |
tree | 409bc505b062ebe10d9468f9d71c2285ebebb6ba /src/fs/gnunet-auto-share.c | |
parent | a31b6d486baee50c455914f292c2f14e52e398f8 (diff) | |
download | gnunet-2b7808e952a77f2cb951d81f3308a9fbaf4e56ec.tar.gz gnunet-2b7808e952a77f2cb951d81f3308a9fbaf4e56ec.zip |
-more skeleton work for gnunet-auto-share
Diffstat (limited to 'src/fs/gnunet-auto-share.c')
-rw-r--r-- | src/fs/gnunet-auto-share.c | 306 |
1 files changed, 298 insertions, 8 deletions
diff --git a/src/fs/gnunet-auto-share.c b/src/fs/gnunet-auto-share.c index e076d8b31..01c48aab0 100644 --- a/src/fs/gnunet-auto-share.c +++ b/src/fs/gnunet-auto-share.c | |||
@@ -26,35 +26,316 @@ | |||
26 | #include "gnunet_util_lib.h" | 26 | #include "gnunet_util_lib.h" |
27 | 27 | ||
28 | 28 | ||
29 | /** | ||
30 | * Item in our work queue (or in the set of files/directories | ||
31 | * we have successfully published). | ||
32 | */ | ||
33 | struct WorkItem | ||
34 | { | ||
35 | |||
36 | /** | ||
37 | * PENDING Work is kept in a linked list. | ||
38 | */ | ||
39 | struct WorkItem *prev; | ||
40 | |||
41 | /** | ||
42 | * PENDING Work is kept in a linked list. | ||
43 | */ | ||
44 | struct WorkItem *next; | ||
45 | |||
46 | /** | ||
47 | * Filename of the work item. | ||
48 | */ | ||
49 | const char *filename; | ||
50 | |||
51 | /** | ||
52 | * Unique identity for this work item (used to detect | ||
53 | * if we need to do the work again). | ||
54 | */ | ||
55 | struct GNUNET_HashCode id; | ||
56 | }; | ||
57 | |||
58 | |||
59 | /** | ||
60 | * Global return value from 'main'. | ||
61 | */ | ||
29 | static int ret; | 62 | static int ret; |
30 | 63 | ||
64 | /** | ||
65 | * Are we running 'verbosely'? | ||
66 | */ | ||
31 | static int verbose; | 67 | static int verbose; |
32 | 68 | ||
69 | /** | ||
70 | * Configuration to use. | ||
71 | */ | ||
33 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 72 | static const struct GNUNET_CONFIGURATION_Handle *cfg; |
34 | 73 | ||
74 | /** | ||
75 | * Disable extractor option to use for publishing. | ||
76 | */ | ||
35 | static int disable_extractor; | 77 | static int disable_extractor; |
36 | 78 | ||
79 | /** | ||
80 | * Disable creation time option to use for publishing. | ||
81 | */ | ||
37 | static int do_disable_creation_time; | 82 | static int do_disable_creation_time; |
38 | 83 | ||
84 | /** | ||
85 | * Handle for the 'shutdown' task. | ||
86 | */ | ||
39 | static GNUNET_SCHEDULER_TaskIdentifier kill_task; | 87 | static GNUNET_SCHEDULER_TaskIdentifier kill_task; |
40 | 88 | ||
89 | /** | ||
90 | * Handle for the main task that does scanning and working. | ||
91 | */ | ||
92 | static GNUNET_SCHEDULER_TaskIdentifier run_task; | ||
93 | |||
94 | /** | ||
95 | * Anonymity level option to use for publishing. | ||
96 | */ | ||
41 | static unsigned int anonymity_level = 1; | 97 | static unsigned int anonymity_level = 1; |
42 | 98 | ||
99 | /** | ||
100 | * Content priority option to use for publishing. | ||
101 | */ | ||
43 | static unsigned int content_priority = 365; | 102 | static unsigned int content_priority = 365; |
44 | 103 | ||
104 | /** | ||
105 | * Replication level option to use for publishing. | ||
106 | */ | ||
45 | static unsigned int replication_level = 1; | 107 | static unsigned int replication_level = 1; |
46 | 108 | ||
109 | /** | ||
110 | * Top-level directory we monitor to auto-publish. | ||
111 | */ | ||
112 | static const char *dir_name; | ||
113 | |||
114 | /** | ||
115 | * Head of linked list of files still to publish. | ||
116 | */ | ||
117 | static struct WorkItem *work_head; | ||
118 | |||
119 | /** | ||
120 | * Tail of linked list of files still to publish. | ||
121 | */ | ||
122 | static struct WorkItem *work_tail; | ||
123 | |||
124 | /** | ||
125 | * Map from the hash of the filename (!) to a 'struct WorkItem' | ||
126 | * that was finished. | ||
127 | */ | ||
128 | static struct GNUNET_CONTAINER_MultiHashMap *work_finished; | ||
129 | |||
130 | /** | ||
131 | * Set to GNUNET_YES if we are shutting down. | ||
132 | */ | ||
133 | static int do_shutdown; | ||
134 | |||
135 | /** | ||
136 | * Start time of the current round; used to determine how long | ||
137 | * one iteration takes (which influences how fast we schedule | ||
138 | * the next one). | ||
139 | */ | ||
140 | static struct GNUNET_TIME_Absolute start_time; | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Load the set of 'work_finished' items from disk. | ||
145 | */ | ||
146 | static void | ||
147 | load_state () | ||
148 | { | ||
149 | GNUNET_break (0); | ||
150 | // FIXME: implement! | ||
151 | } | ||
152 | |||
153 | |||
154 | /** | ||
155 | * Save the set of 'work_finished' items on disk. | ||
156 | */ | ||
157 | static void | ||
158 | save_state () | ||
159 | { | ||
160 | GNUNET_break (0); | ||
161 | // FIXME: implement! | ||
162 | } | ||
163 | |||
47 | 164 | ||
48 | /** | 165 | /** |
49 | * FIXME: docu | 166 | * Task run on shutdown. Serializes our current state to disk. |
167 | * | ||
168 | * @param cls closure, unused | ||
169 | * @param tc scheduler context, unused | ||
50 | */ | 170 | */ |
51 | static void | 171 | static void |
52 | do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 172 | do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
53 | { | 173 | { |
54 | kill_task = GNUNET_SCHEDULER_NO_TASK; | 174 | kill_task = GNUNET_SCHEDULER_NO_TASK; |
175 | do_shutdown = GNUNET_YES; | ||
176 | if (GNUNET_SCHEDULER_NO_TASK != run_task) | ||
177 | { | ||
178 | GNUNET_SCHEDULER_cancel (run_task); | ||
179 | run_task = GNUNET_SCHEDULER_NO_TASK; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | |||
184 | /** | ||
185 | * Decide what the next task is (working or scanning) and schedule it. | ||
186 | */ | ||
187 | static void | ||
188 | schedule_next_task (void); | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Function called to process work items. | ||
193 | * | ||
194 | * @param cls closure, NULL | ||
195 | * @param tc scheduler context (unused) | ||
196 | */ | ||
197 | static void | ||
198 | work (void *cls, | ||
199 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
200 | { | ||
201 | struct WorkItem *wi; | ||
202 | struct GNUNET_HashCode key; | ||
203 | |||
204 | run_task = GNUNET_SCHEDULER_NO_TASK; | ||
205 | wi = work_head; | ||
206 | GNUNET_CONTAINER_DLL_remove (work_head, | ||
207 | work_tail, | ||
208 | wi); | ||
209 | // FIXME: actually run 'publish' here! | ||
210 | |||
211 | GNUNET_CRYPTO_hash (wi->filename, | ||
212 | strlen (wi->filename), | ||
213 | &key); | ||
214 | GNUNET_CONTAINER_multihashmap_put (work_finished, | ||
215 | &key, | ||
216 | wi, | ||
217 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
218 | save_state (); | ||
219 | schedule_next_task (); | ||
220 | } | ||
221 | |||
222 | |||
223 | /** | ||
224 | * Recursively scan the given file/directory structure to determine | ||
225 | * a unique ID that represents the current state of the hierarchy. | ||
226 | * | ||
227 | * @param filename file to scan | ||
228 | * @param id where to store the unique ID we computed | ||
229 | */ | ||
230 | static void | ||
231 | determine_id (const char *filename, | ||
232 | struct GNUNET_HashCode *id) | ||
233 | { | ||
234 | // FIXME: implement! | ||
235 | GNUNET_break (0); | ||
236 | } | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Function called with a filename (or directory name) to publish | ||
241 | * (if it has changed since the last time we published it). This function | ||
242 | * is called for the top-level files only. | ||
243 | * | ||
244 | * @param cls closure, NULL | ||
245 | * @param filename complete filename (absolute path) | ||
246 | * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR during shutdown | ||
247 | */ | ||
248 | static int | ||
249 | add_file (void *cls, | ||
250 | const char *filename) | ||
251 | { | ||
252 | struct WorkItem *wi; | ||
253 | struct GNUNET_HashCode key; | ||
254 | struct GNUNET_HashCode id; | ||
255 | |||
256 | if (GNUNET_YES == do_shutdown) | ||
257 | return GNUNET_SYSERR; | ||
258 | GNUNET_CRYPTO_hash (filename, | ||
259 | strlen (filename), | ||
260 | &key); | ||
261 | wi = GNUNET_CONTAINER_multihashmap_get (work_finished, | ||
262 | &key); | ||
263 | memset (&id, 0, sizeof (struct GNUNET_HashCode)); | ||
264 | determine_id (filename, &id); | ||
265 | if (NULL != wi) | ||
266 | { | ||
267 | if (0 == memcmp (&id, | ||
268 | &wi->id, | ||
269 | sizeof (struct GNUNET_HashCode))) | ||
270 | return GNUNET_OK; /* skip: we did this one already */ | ||
271 | /* contents changed, need to re-do the directory... */ | ||
272 | GNUNET_CONTAINER_multihashmap_remove (work_finished, | ||
273 | &key, | ||
274 | wi); | ||
275 | wi->id = id; | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | wi = GNUNET_malloc (sizeof (struct WorkItem)); | ||
280 | wi->filename = GNUNET_strdup (filename); | ||
281 | } | ||
282 | GNUNET_CONTAINER_DLL_insert (work_head, | ||
283 | work_tail, | ||
284 | wi); | ||
285 | if (GNUNET_YES == do_shutdown) | ||
286 | return GNUNET_SYSERR; | ||
287 | return GNUNET_OK; | ||
288 | } | ||
289 | |||
290 | |||
291 | /** | ||
292 | * Periodically run task to update our view of the directory to share. | ||
293 | * | ||
294 | * @param cls NULL | ||
295 | * @param tc scheduler context, unused | ||
296 | */ | ||
297 | static void | ||
298 | scan (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
299 | { | ||
300 | run_task = GNUNET_SCHEDULER_NO_TASK; | ||
301 | start_time = GNUNET_TIME_absolute_get (); | ||
302 | (void) GNUNET_DISK_directory_scan (dir_name, | ||
303 | &add_file, | ||
304 | NULL); | ||
305 | schedule_next_task (); | ||
55 | } | 306 | } |
56 | 307 | ||
57 | 308 | ||
309 | /** | ||
310 | * Decide what the next task is (working or scanning) and schedule it. | ||
311 | */ | ||
312 | static void | ||
313 | schedule_next_task () | ||
314 | { | ||
315 | struct GNUNET_TIME_Relative delay; | ||
316 | |||
317 | if (GNUNET_YES == do_shutdown) | ||
318 | return; | ||
319 | if (NULL == work_head) | ||
320 | { | ||
321 | /* delay by at most 4h, at least 1s, and otherwise in between depending | ||
322 | on how long it took to scan */ | ||
323 | delay = GNUNET_TIME_absolute_get_duration (start_time); | ||
324 | delay = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, | ||
325 | 4), | ||
326 | GNUNET_TIME_relative_multiply (delay, | ||
327 | 100)); | ||
328 | delay = GNUNET_TIME_relative_max (delay, | ||
329 | GNUNET_TIME_UNIT_MINUTES); | ||
330 | run_task = GNUNET_SCHEDULER_add_delayed (delay, | ||
331 | &scan, | ||
332 | NULL); | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | run_task = GNUNET_SCHEDULER_add_now (&work, NULL); | ||
337 | } | ||
338 | } | ||
58 | 339 | ||
59 | 340 | ||
60 | /** | 341 | /** |
@@ -78,7 +359,12 @@ run (void *cls, char *const *args, const char *cfgfile, | |||
78 | return; | 359 | return; |
79 | } | 360 | } |
80 | cfg = c; | 361 | cfg = c; |
81 | // FIXME... | 362 | dir_name = args[0]; |
363 | work_finished = GNUNET_CONTAINER_multihashmap_create (1024); | ||
364 | load_state (); | ||
365 | run_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
366 | &scan, NULL); | ||
367 | |||
82 | kill_task = | 368 | kill_task = |
83 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, | 369 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, |
84 | NULL); | 370 | NULL); |
@@ -94,7 +380,7 @@ run (void *cls, char *const *args, const char *cfgfile, | |||
94 | */ | 380 | */ |
95 | int | 381 | int |
96 | main (int argc, char *const *argv) | 382 | main (int argc, char *const *argv) |
97 | { | 383 | { |
98 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | 384 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { |
99 | {'a', "anonymity", "LEVEL", | 385 | {'a', "anonymity", "LEVEL", |
100 | gettext_noop ("set the desired LEVEL of sender-anonymity"), | 386 | gettext_noop ("set the desired LEVEL of sender-anonymity"), |
@@ -117,13 +403,17 @@ main (int argc, char *const *argv) | |||
117 | 0, &GNUNET_GETOPT_set_one, &verbose}, | 403 | 0, &GNUNET_GETOPT_set_one, &verbose}, |
118 | GNUNET_GETOPT_OPTION_END | 404 | GNUNET_GETOPT_OPTION_END |
119 | }; | 405 | }; |
406 | int ok; | ||
407 | |||
120 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | 408 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) |
121 | return 2; | 409 | return 2; |
122 | return (GNUNET_OK == | 410 | ok = (GNUNET_OK == |
123 | GNUNET_PROGRAM_run (argc, argv, "gnunet-auto-share [OPTIONS] FILENAME", | 411 | GNUNET_PROGRAM_run (argc, argv, "gnunet-auto-share [OPTIONS] FILENAME", |
124 | gettext_noop | 412 | gettext_noop |
125 | ("Automatically publish files from a directory on GNUnet"), | 413 | ("Automatically publish files from a directory on GNUnet"), |
126 | options, &run, NULL)) ? ret : 1; | 414 | options, &run, NULL)) ? ret : 1; |
415 | // FIXME: free memory in work lists and hash map... | ||
416 | return ok; | ||
127 | } | 417 | } |
128 | 418 | ||
129 | /* end of gnunet-auto-share.c */ | 419 | /* end of gnunet-auto-share.c */ |