2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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 2, or (at your
8 option) any later version.
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.
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.
22 * @file fs/fs_publish.c
23 * @brief publish a file or directory in GNUnet
24 * @see http://gnunet.org/encoding.php3
25 * @author Krista Bennett
26 * @author Christian Grothoff
29 * - code-sharing with unindex (write unindex code, clean up new FIXME's)
30 * - indexing cleanup: unindex on failure (can wait)
31 * - persistence support (can wait)
32 * - datastore reservation support (optimization)
33 * - location URIs (publish with anonymity-level zero)
37 #include "gnunet_constants.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_util_lib.h"
40 #include "gnunet_fs_service.h"
44 #define DEBUG_PUBLISH GNUNET_YES
47 * Maximum allowed size for a KBlock.
49 #define MAX_KBLOCK_SIZE 60000
52 * Maximum allowed size for an SBlock.
54 #define MAX_SBLOCK_SIZE 60000
57 * Main function that performs the upload.
58 * @param cls "struct GNUNET_FS_PublishContext" identifies the upload
59 * @param tc task context
63 const struct GNUNET_SCHEDULER_TaskContext *tc);
67 * Context for "ds_put_cont".
72 * Current publishing context.
74 struct GNUNET_FS_PublishContext *sc;
77 * Specific file with the block.
79 struct GNUNET_FS_FileInformation *p;
82 * Function to run next, if any (can be NULL).
84 GNUNET_SCHEDULER_Task cont;
94 * Fill in all of the generic fields for
97 * @param pc structure to fill in
98 * @param sc overall publishing context
99 * @param p file information for the file being published
102 make_publish_status (struct GNUNET_FS_ProgressInfo *pi,
103 struct GNUNET_FS_PublishContext *sc,
104 const struct GNUNET_FS_FileInformation *p)
106 pi->value.publish.sc = sc;
107 pi->value.publish.fi = p;
108 pi->value.publish.cctx
110 pi->value.publish.pctx
111 = (NULL == p->dir) ? NULL : p->dir->client_info;
112 pi->value.publish.size
113 = (p->is_directory) ? p->data.dir.dir_size : p->data.file.file_size;
115 pi->value.publish.eta
116 = GNUNET_TIME_calculate_eta (p->start_time,
118 pi->value.publish.size);
119 pi->value.publish.completed = p->publish_offset;
121 pi->value.publish.duration = GNUNET_TIME_absolute_get_duration (p->start_time);
122 pi->value.publish.anonymity = p->anonymity;
127 * Cleanup the publish context, we're done
130 * @param pc struct to clean up after
133 publish_cleanup (struct GNUNET_FS_PublishContext *sc)
135 GNUNET_FS_file_information_destroy (sc->fi, NULL, NULL);
136 GNUNET_FS_namespace_delete (sc->namespace, GNUNET_NO);
137 GNUNET_free_non_null (sc->nid);
138 GNUNET_free_non_null (sc->nuid);
139 GNUNET_DATASTORE_disconnect (sc->dsh, GNUNET_NO);
145 * Function called by the datastore API with
146 * the result from the PUT request.
148 * @param cls our closure
149 * @param success GNUNET_OK on success
150 * @param msg error message (or NULL)
153 ds_put_cont (void *cls,
157 struct PutContCtx *pcc = cls;
158 struct GNUNET_FS_ProgressInfo pi;
160 if (GNUNET_SYSERR == pcc->sc->in_network_wait)
162 /* we were aborted in the meantime,
164 publish_cleanup (pcc->sc);
167 GNUNET_assert (GNUNET_YES == pcc->sc->in_network_wait);
168 pcc->sc->in_network_wait = GNUNET_NO;
169 if (GNUNET_OK != success)
171 GNUNET_asprintf (&pcc->p->emsg,
172 _("Upload failed: %s"),
174 GNUNET_FS_file_information_sync (pcc->p);
175 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
176 make_publish_status (&pi, pcc->sc, pcc->p);
177 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
178 pi.value.publish.specifics.error.message = pcc->p->emsg;
180 = pcc->sc->h->upcb (pcc->sc->h->upcb_cls,
184 GNUNET_FS_file_information_sync (pcc->p);
185 if (NULL != pcc->cont)
187 = GNUNET_SCHEDULER_add_delayed (pcc->sc->h->sched,
189 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
190 GNUNET_SCHEDULER_NO_TASK,
191 GNUNET_TIME_UNIT_ZERO,
199 * Generate the callback that signals clients
200 * that a file (or directory) has been completely
203 * @param p the completed upload
204 * @param sc context of the publication
207 signal_publish_completion (struct GNUNET_FS_FileInformation *p,
208 struct GNUNET_FS_PublishContext *sc)
210 struct GNUNET_FS_ProgressInfo pi;
212 pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED;
213 make_publish_status (&pi, sc, p);
214 pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO;
215 pi.value.publish.specifics.completed.chk_uri = p->chk_uri;
217 = sc->h->upcb (sc->h->upcb_cls,
223 * Generate the callback that signals clients
224 * that a file (or directory) has encountered
225 * a problem during publication.
227 * @param p the upload that had trouble
228 * @param sc context of the publication
229 * @param emsg error message
232 signal_publish_error (struct GNUNET_FS_FileInformation *p,
233 struct GNUNET_FS_PublishContext *sc,
236 struct GNUNET_FS_ProgressInfo pi;
238 p->emsg = GNUNET_strdup (emsg);
239 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
240 make_publish_status (&pi, sc, p);
241 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
242 pi.value.publish.specifics.error.message =emsg;
244 = sc->h->upcb (sc->h->upcb_cls,
250 * We've finished publishing the SBlock as part of a larger upload.
251 * Check the result and complete the larger upload.
253 * @param cls the "struct GNUNET_FS_PublishContext*" of the larger upload
254 * @param uri URI of the published SBlock
255 * @param emsg NULL on success, otherwise error message
258 publish_sblocks_cont (void *cls,
259 const struct GNUNET_FS_Uri *uri,
262 struct GNUNET_FS_PublishContext *sc = cls;
265 signal_publish_error (sc->fi,
270 // FIXME: release the datastore reserve here!
271 signal_publish_completion (sc->fi, sc);
276 * We are almost done publishing the structure,
277 * add SBlocks (if needed).
279 * @param sc overall upload data
282 publish_sblock (struct GNUNET_FS_PublishContext *sc)
284 if (NULL != sc->namespace)
285 GNUNET_FS_publish_sks (sc->h,
291 sc->fi->expirationTime,
295 &publish_sblocks_cont,
298 publish_sblocks_cont (sc, NULL, NULL);
303 * We've finished publishing a KBlock
304 * as part of a larger upload. Check
305 * the result and continue the larger
308 * @param cls the "struct GNUNET_FS_PublishContext*"
309 * of the larger upload
310 * @param uri URI of the published blocks
311 * @param emsg NULL on success, otherwise error message
314 publish_kblocks_cont (void *cls,
315 const struct GNUNET_FS_Uri *uri,
318 struct GNUNET_FS_PublishContext *sc = cls;
319 struct GNUNET_FS_FileInformation *p = sc->fi_pos;
323 signal_publish_error (p, sc, emsg);
325 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
327 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
328 GNUNET_SCHEDULER_NO_TASK,
329 GNUNET_TIME_UNIT_ZERO,
334 GNUNET_FS_file_information_sync (p);
336 signal_publish_completion (p, sc);
337 /* move on to next file */
339 sc->fi_pos = p->next;
343 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
345 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
346 GNUNET_SCHEDULER_NO_TASK,
347 GNUNET_TIME_UNIT_ZERO,
355 block_reader (void *cls,
361 struct GNUNET_FS_PublishContext *sc = cls;
362 struct GNUNET_FS_FileInformation *p;
369 pt_size = GNUNET_MIN(max,
370 p->data.dir.dir_size - offset);
371 dd = p->data.dir.dir_data;
378 pt_size = GNUNET_MIN(max,
379 p->data.file.file_size - offset);
381 p->data.file.reader (p->data.file.reader_cls,
394 encode_cont (void *cls,
395 const struct GNUNET_SCHEDULER_TaskContext *tc)
397 struct GNUNET_FS_PublishContext *sc = cls;
398 struct GNUNET_FS_FileInformation *p;
399 struct GNUNET_FS_ProgressInfo pi;
403 GNUNET_FS_tree_encoder_finish (p->te,
409 GNUNET_asprintf (&p->emsg,
410 _("Upload failed: %s"),
413 GNUNET_FS_file_information_sync (p);
414 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
415 make_publish_status (&pi, sc, p);
416 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
417 pi.value.publish.specifics.error.message = p->emsg;
419 = sc->h->upcb (sc->h->upcb_cls,
422 /* continue with main */
424 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
426 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
427 GNUNET_SCHEDULER_NO_TASK,
428 GNUNET_TIME_UNIT_ZERO,
435 * Function called asking for the current (encoded)
436 * block to be processed. After processing the
437 * client should either call "GNUNET_FS_tree_encode_next"
438 * or (on error) "GNUNET_FS_tree_encode_finish".
441 * @param query the query for the block (key for lookup in the datastore)
442 * @param type type of the block (IBLOCK or DBLOCK)
443 * @param block the (encrypted) block
444 * @param block_size size of block (in bytes)
447 block_proc (void *cls,
448 const GNUNET_HashCode *query,
454 struct GNUNET_FS_PublishContext *sc = cls;
455 struct GNUNET_FS_FileInformation *p;
456 struct PutContCtx * dpc_cls;
457 struct OnDemandBlock odb;
463 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
465 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
466 GNUNET_SCHEDULER_NO_TASK,
467 GNUNET_TIME_UNIT_ZERO,
473 GNUNET_assert (GNUNET_NO == sc->in_network_wait);
474 sc->in_network_wait = GNUNET_YES;
475 dpc_cls = GNUNET_malloc(sizeof(struct PutContCtx));
476 dpc_cls->cont = &do_upload;
477 dpc_cls->cont_cls = sc;
479 if ( (p->is_directory) &&
480 (p->data.file.do_index) &&
481 (type == GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) )
484 odb.file_id = p->data.file.file_id;
485 GNUNET_DATASTORE_put (sc->dsh,
488 sizeof(struct OnDemandBlock),
490 GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND,
494 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
499 GNUNET_DATASTORE_put (sc->dsh,
508 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
515 * Function called with information about our
516 * progress in computing the tree encoding.
519 * @param offset where are we in the file
520 * @param pt_block plaintext of the currently processed block
521 * @param pt_size size of pt_block
522 * @param depth depth of the block in the tree
525 progress_proc (void *cls,
527 const void *pt_block,
531 struct GNUNET_FS_PublishContext *sc = cls;
532 struct GNUNET_FS_FileInformation *p;
533 struct GNUNET_FS_ProgressInfo pi;
536 pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS;
537 make_publish_status (&pi, sc, p);
538 pi.value.publish.specifics.progress.data = pt_block;
539 pi.value.publish.specifics.progress.offset = offset;
540 pi.value.publish.specifics.progress.data_len = pt_size;
541 // FIXME: add depth to pi
543 = sc->h->upcb (sc->h->upcb_cls,
549 * We are uploading a file or directory; load (if necessary) the next
550 * block into memory, encrypt it and send it to the FS service. Then
551 * continue with the main task.
553 * @param sc overall upload data
554 * @param p specific file or directory for which kblocks
557 // FIXME: "p" argument is not needed!
559 publish_content (struct GNUNET_FS_PublishContext *sc,
560 struct GNUNET_FS_FileInformation *p)
563 struct GNUNET_FS_DirectoryBuilder *db;
564 struct GNUNET_FS_FileInformation *dirpos;
572 db = GNUNET_FS_directory_builder_create (p->meta);
573 dirpos = p->data.dir.entries;
574 while (NULL != dirpos)
576 if (dirpos->is_directory)
578 raw_data = dirpos->data.dir.dir_data;
579 dirpos->data.dir.dir_data = NULL;
584 if ( (dirpos->data.file.file_size < MAX_INLINE_SIZE) &&
585 (dirpos->data.file.file_size > 0) )
587 raw_data = GNUNET_malloc (dirpos->data.file.file_size);
589 if (dirpos->data.file.file_size !=
590 dirpos->data.file.reader (dirpos->data.file.reader_cls,
592 dirpos->data.file.file_size,
596 GNUNET_free_non_null (emsg);
597 GNUNET_free (raw_data);
602 GNUNET_FS_directory_builder_add (db,
606 GNUNET_free_non_null (raw_data);
607 dirpos = dirpos->next;
609 GNUNET_FS_directory_builder_finish (db,
610 &p->data.dir.dir_size,
611 &p->data.dir.dir_data);
613 size = (p->is_directory)
614 ? p->data.dir.dir_size
615 : p->data.file.file_size;
616 p->te = GNUNET_FS_tree_encoder_create (sc->h,
625 GNUNET_FS_tree_encoder_next (p->te);
630 * Process the response (or lack thereof) from
631 * the "fs" service to our 'start index' request.
633 * @param cls closure (of type "struct GNUNET_FS_PublishContext*"_)
634 * @param msg the response we got
637 process_index_start_response (void *cls,
638 const struct GNUNET_MessageHeader *msg)
640 struct GNUNET_FS_PublishContext *sc = cls;
641 struct GNUNET_FS_FileInformation *p;
645 GNUNET_CLIENT_disconnect (sc->client);
650 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
651 _("Can not index file `%s': %s. Will try to insert instead.\n"),
652 p->data.file.filename,
653 _("timeout on index-start request to `fs' service"));
654 p->data.file.do_index = GNUNET_NO;
655 publish_content (sc, p);
658 if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK)
660 msize = ntohs (msg->size);
661 emsg = (const char *) &msg[1];
662 if ( (msize <= sizeof (struct GNUNET_MessageHeader)) ||
663 (emsg[msize - sizeof(struct GNUNET_MessageHeader) - 1] != '\0') )
664 emsg = gettext_noop ("unknown error");
665 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
666 _("Can not index file `%s': %s. Will try to insert instead.\n"),
667 p->data.file.filename,
669 p->data.file.do_index = GNUNET_NO;
670 publish_content (sc, p);
673 /* success! continue with indexing */
674 publish_content (sc, p);
679 #include <sys/statvfs.h>
683 * Function called once the hash computation over an
684 * indexed file has completed.
686 * @param cls closure, our publishing context
687 * @param res resulting hash, NULL on error
690 hash_for_index_cb (void *cls,
691 const GNUNET_HashCode *
694 struct GNUNET_FS_PublishContext *sc = cls;
695 struct GNUNET_FS_FileInformation *p;
696 struct IndexStartMessage *ism;
698 struct GNUNET_CLIENT_Connection *client;
707 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
708 _("Can not index file `%s': %s. Will try to insert instead.\n"),
709 p->data.file.filename,
710 _("failed to compute hash"));
711 p->data.file.do_index = GNUNET_NO;
712 publish_content (sc, p);
715 slen = strlen (p->data.file.filename) + 1;
716 if (slen > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof(struct IndexStartMessage))
718 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
719 _("Can not index file `%s': %s. Will try to insert instead.\n"),
720 p->data.file.filename,
721 _("filename too long"));
722 p->data.file.do_index = GNUNET_NO;
723 publish_content (sc, p);
726 client = GNUNET_CLIENT_connect (sc->h->sched,
731 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
732 _("Can not index file `%s': %s. Will try to insert instead.\n"),
733 p->data.file.filename,
734 _("could not connect to `fs' service"));
735 p->data.file.do_index = GNUNET_NO;
736 publish_content (sc, p);
739 p->data.file.file_id = *res;
740 ism = GNUNET_malloc (sizeof(struct IndexStartMessage) +
742 ism->header.size = htons(sizeof(struct IndexStartMessage) +
744 ism->header.type = htons(GNUNET_MESSAGE_TYPE_FS_INDEX_START);
745 /* FIXME: activate this on other OSes that
746 support it (or something very similar; make
747 sure to also adjust corresponding code
748 on the service-side) */
749 /* FIXME: the block below should probably be
750 abstracted into a function in the DISK API */
752 if ( (0 == stat(p->data.file.filename,
754 (0 == statvfs (p->data.file.filename,
757 ism->device = htonl ((uint32_t) fbuf.f_fsid);
758 ism->inode = GNUNET_htonll( (uint64_t) sbuf.st_ino);
762 p->data.file.filename,
765 GNUNET_CLIENT_transmit_and_get_response (client,
767 GNUNET_TIME_UNIT_FOREVER_REL,
768 &process_index_start_response,
775 * Main function that performs the upload.
776 * @param cls "struct GNUNET_FS_PublishContext" identifies the upload
777 * @param tc task context
780 do_upload (void *cls,
781 const struct GNUNET_SCHEDULER_TaskContext *tc)
783 struct GNUNET_FS_PublishContext *sc = cls;
784 struct GNUNET_FS_ProgressInfo pi;
785 struct GNUNET_FS_FileInformation *p;
788 sc->upload_task = GNUNET_SCHEDULER_NO_TASK;
792 /* upload of entire hierarchy complete,
793 publish namespace entries */
797 /* find starting position */
798 while ( (p->is_directory) &&
799 (NULL != p->data.dir.entries) &&
801 (NULL == p->data.dir.entries->chk_uri) )
803 p = p->data.dir.entries;
809 /* error with current file, abort all
810 related files as well! */
811 while (NULL != p->dir)
813 fn = GNUNET_CONTAINER_meta_data_get_by_type (p->meta,
816 GNUNET_asprintf (&p->emsg,
817 _("Recursive upload failed at `%s'"),
820 GNUNET_FS_file_information_sync (p);
821 pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR;
822 make_publish_status (&pi, sc, p);
823 pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL;
824 pi.value.publish.specifics.error.message = p->emsg;
826 = sc->h->upcb (sc->h->upcb_cls,
831 /* handle completion */
832 if (NULL != p->chk_uri)
834 /* upload of "p" complete, publish KBlocks! */
835 GNUNET_FS_publish_ksk (sc->h,
843 &publish_kblocks_cont,
847 if ( (!p->is_directory) &&
848 (p->data.file.do_index) )
850 if (NULL == p->data.file.filename)
852 p->data.file.do_index = GNUNET_NO;
853 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
854 _("Can not index file `%s': %s. Will try to insert instead.\n"),
856 _("needs to be an actual file"));
857 publish_content (sc, p);
860 GNUNET_CRYPTO_hash_file (sc->h->sched,
861 GNUNET_SCHEDULER_PRIORITY_IDLE,
863 p->data.file.filename,
869 publish_content (sc, p);
874 * Signal the FS's progress function that we are starting
877 * @param cls closure (of type "struct GNUNET_FS_PublishContext*")
878 * @param fi the entry in the publish-structure
879 * @param length length of the file or directory
880 * @param meta metadata for the file or directory (can be modified)
881 * @param uri pointer to the keywords that will be used for this entry (can be modified)
882 * @param anonymity pointer to selected anonymity level (can be modified)
883 * @param priority pointer to selected priority (can be modified)
884 * @param expirationTime pointer to selected expiration time (can be modified)
885 * @param client_info pointer to client context set upon creation (can be modified)
886 * @return GNUNET_OK to continue (always)
889 fip_signal_start(void *cls,
890 struct GNUNET_FS_FileInformation *fi,
892 struct GNUNET_CONTAINER_MetaData *meta,
893 struct GNUNET_FS_Uri **uri,
894 unsigned int *anonymity,
895 unsigned int *priority,
896 struct GNUNET_TIME_Absolute *expirationTime,
899 struct GNUNET_FS_PublishContext *sc = cls;
900 struct GNUNET_FS_ProgressInfo pi;
902 pi.status = GNUNET_FS_STATUS_PUBLISH_START;
903 make_publish_status (&pi, sc, fi);
904 *client_info = sc->h->upcb (sc->h->upcb_cls,
911 * Publish a file or directory.
913 * @param h handle to the file sharing subsystem
914 * @param ctx initial value to use for the '*ctx'
915 * in the callback (for the GNUNET_FS_STATUS_PUBLISH_START event).
916 * @param fi information about the file or directory structure to publish
917 * @param namespace namespace to publish the file in, NULL for no namespace
918 * @param nid identifier to use for the publishd content in the namespace
919 * (can be NULL, must be NULL if namespace is NULL)
920 * @param nuid update-identifier that will be used for future updates
921 * (can be NULL, must be NULL if namespace or nid is NULL)
922 * @param options options for the publication
923 * @return context that can be used to control the publish operation
925 struct GNUNET_FS_PublishContext *
926 GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h,
928 struct GNUNET_FS_FileInformation *fi,
929 struct GNUNET_FS_Namespace *namespace,
932 enum GNUNET_FS_PublishOptions options)
934 struct GNUNET_FS_PublishContext *ret;
935 struct GNUNET_DATASTORE_Handle *dsh;
937 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
939 dsh = GNUNET_DATASTORE_connect (h->cfg,
948 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext));
951 ret->client_ctx = ctx;
953 ret->namespace = namespace;
954 if (namespace != NULL)
957 GNUNET_assert (NULL != nid);
958 ret->nid = GNUNET_strdup (nid);
960 ret->nuid = GNUNET_strdup (nuid);
962 // FIXME: make upload persistent!
965 GNUNET_FS_file_information_inspect (ret->fi,
968 ret->fi_pos = ret->fi;
970 // FIXME: calculate space needed for "fi"
971 // and reserve as first task (then trigger
972 // "do_upload" from that continuation)!
974 = GNUNET_SCHEDULER_add_delayed (h->sched,
976 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
977 GNUNET_SCHEDULER_NO_TASK,
978 GNUNET_TIME_UNIT_ZERO,
986 * Signal the FS's progress function that we are stopping
989 * @param cls closure (of type "struct GNUNET_FS_PublishContext*")
990 * @param fi the entry in the publish-structure
991 * @param length length of the file or directory
992 * @param meta metadata for the file or directory (can be modified)
993 * @param uri pointer to the keywords that will be used for this entry (can be modified)
994 * @param anonymity pointer to selected anonymity level (can be modified)
995 * @param priority pointer to selected priority (can be modified)
996 * @param expirationTime pointer to selected expiration time (can be modified)
997 * @param client_info pointer to client context set upon creation (can be modified)
998 * @return GNUNET_OK to continue (always)
1001 fip_signal_stop(void *cls,
1002 struct GNUNET_FS_FileInformation *fi,
1004 struct GNUNET_CONTAINER_MetaData *meta,
1005 struct GNUNET_FS_Uri **uri,
1006 unsigned int *anonymity,
1007 unsigned int *priority,
1008 struct GNUNET_TIME_Absolute *expirationTime,
1011 struct GNUNET_FS_PublishContext*sc = cls;
1012 struct GNUNET_FS_ProgressInfo pi;
1014 pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED;
1015 make_publish_status (&pi, sc, fi);
1016 GNUNET_break (NULL ==
1017 sc->h->upcb (sc->h->upcb_cls,
1019 *client_info = NULL;
1025 * Stop an upload. Will abort incomplete uploads (but
1026 * not remove blocks that have already been publishd) or
1027 * simply clean up the state for completed uploads.
1029 * @param sc context for the upload to stop
1032 GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *sc)
1034 if (GNUNET_SCHEDULER_NO_TASK != sc->upload_task)
1035 GNUNET_SCHEDULER_cancel (sc->h->sched, sc->upload_task);
1036 // FIXME: remove from persistence DB (?) --- think more about
1037 // shutdown / persistent-resume APIs!!!
1038 GNUNET_FS_file_information_inspect (sc->fi,
1041 if (GNUNET_YES == sc->in_network_wait)
1043 sc->in_network_wait = GNUNET_SYSERR;
1046 publish_cleanup (sc);
1051 * Context for the KSK publication.
1053 struct PublishKskContext
1059 struct GNUNET_FS_Uri *ksk_uri;
1062 * Global FS context.
1064 struct GNUNET_FS_Handle *h;
1067 * The master block that we are sending
1068 * (in plaintext), has "mdsize+slen" more
1069 * bytes than the struct would suggest.
1074 * Buffer of the same size as "kb" for
1075 * the encrypted version.
1080 * Handle to the datastore, NULL if we are just
1083 struct GNUNET_DATASTORE_Handle *dsh;
1086 * Function to call once we're done.
1088 GNUNET_FS_PublishContinuation cont;
1096 * When should the KBlocks expire?
1098 struct GNUNET_TIME_Absolute expirationTime;
1101 * Size of the serialized metadata.
1106 * Size of the (CHK) URI as a string.
1111 * Keyword that we are currently processing.
1116 * Anonymity level for the KBlocks.
1118 unsigned int anonymity;
1121 * Priority for the KBlocks.
1123 unsigned int priority;
1128 * Continuation of "GNUNET_FS_publish_ksk" that performs
1129 * the actual publishing operation (iterating over all
1132 * @param cls closure of type "struct PublishKskContext*"
1136 publish_ksk_cont (void *cls,
1137 const struct GNUNET_SCHEDULER_TaskContext *tc);
1141 * Function called by the datastore API with
1142 * the result from the PUT request.
1144 * @param cls closure of type "struct PublishKskContext*"
1145 * @param success GNUNET_OK on success
1146 * @param msg error message (or NULL)
1149 kb_put_cont (void *cls,
1153 struct PublishKskContext *pkc = cls;
1155 if (GNUNET_OK != success)
1157 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1158 GNUNET_free (pkc->cpy);
1159 GNUNET_free (pkc->kb);
1160 pkc->cont (pkc->cont_cls,
1163 GNUNET_FS_uri_destroy (pkc->ksk_uri);
1167 GNUNET_SCHEDULER_add_continuation (pkc->h->sched,
1171 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1176 * Continuation of "GNUNET_FS_publish_ksk" that performs
1177 * the actual publishing operation (iterating over all
1180 * @param cls closure of type "struct PublishKskContext*"
1184 publish_ksk_cont (void *cls,
1185 const struct GNUNET_SCHEDULER_TaskContext *tc)
1187 struct PublishKskContext *pkc = cls;
1188 const char *keyword;
1189 GNUNET_HashCode key;
1190 GNUNET_HashCode query;
1191 struct GNUNET_CRYPTO_AesSessionKey skey;
1192 struct GNUNET_CRYPTO_AesInitializationVector iv;
1193 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
1196 if ( (pkc->i == pkc->ksk_uri->data.ksk.keywordCount) ||
1197 (NULL == pkc->dsh) )
1199 if (NULL != pkc->dsh)
1200 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1201 GNUNET_free (pkc->cpy);
1202 GNUNET_free (pkc->kb);
1203 pkc->cont (pkc->cont_cls,
1206 GNUNET_FS_uri_destroy (pkc->ksk_uri);
1210 keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
1211 /* first character of keyword indicates if it is
1212 mandatory or not -- ignore for hashing */
1213 GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
1214 GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
1215 GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1],
1216 pkc->slen + pkc->mdsize,
1220 pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
1221 GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace);
1222 GNUNET_CRYPTO_hash (&pkc->cpy->keyspace,
1223 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1225 GNUNET_assert (GNUNET_OK ==
1226 GNUNET_CRYPTO_rsa_sign (pk,
1228 &pkc->cpy->signature));
1229 GNUNET_CRYPTO_rsa_key_free (pk);
1230 GNUNET_DATASTORE_put (pkc->dsh,
1234 sizeof (struct KBlock) +
1237 GNUNET_DATASTORE_BLOCKTYPE_KBLOCK,
1240 pkc->expirationTime,
1241 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1248 * Publish a CHK under various keywords on GNUnet.
1250 * @param h handle to the file sharing subsystem
1251 * @param ksk_uri keywords to use
1252 * @param meta metadata to use
1253 * @param uri URI to refer to in the KBlock
1254 * @param expirationTime when the KBlock expires
1255 * @param anonymity anonymity level for the KBlock
1256 * @param priority priority for the KBlock
1257 * @param options publication options
1258 * @param cont continuation
1259 * @param cont_cls closure for cont
1262 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
1263 struct GNUNET_FS_Uri *ksk_uri,
1264 struct GNUNET_CONTAINER_MetaData *meta,
1265 struct GNUNET_FS_Uri *uri,
1266 struct GNUNET_TIME_Absolute expirationTime,
1267 unsigned int anonymity,
1268 unsigned int priority,
1269 enum GNUNET_FS_PublishOptions options,
1270 GNUNET_FS_PublishContinuation cont,
1273 struct PublishKskContext *pkc;
1278 pkc = GNUNET_malloc (sizeof (struct PublishKskContext));
1280 pkc->expirationTime = expirationTime;
1281 pkc->anonymity = anonymity;
1282 pkc->priority = priority;
1284 pkc->cont_cls = cont_cls;
1285 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1287 pkc->dsh = GNUNET_DATASTORE_connect (h->cfg,
1289 if (pkc->dsh == NULL)
1291 cont (cont_cls, NULL, _("Could not connect to datastore."));
1296 pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1297 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1298 GNUNET_assert (pkc->mdsize >= 0);
1299 uris = GNUNET_FS_uri_to_string (uri);
1300 pkc->slen = strlen (uris) + 1;
1301 size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen;
1302 if (size > MAX_KBLOCK_SIZE)
1304 size = MAX_KBLOCK_SIZE;
1305 pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen;
1307 pkc->kb = GNUNET_malloc (size);
1308 kbe = (char *) &pkc->kb[1];
1309 memcpy (kbe, uris, pkc->slen);
1311 pkc->mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1314 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1315 if (pkc->mdsize == -1)
1319 GNUNET_free (pkc->kb);
1320 if (pkc->dsh != NULL)
1321 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
1322 cont (cont_cls, NULL, _("Internal error."));
1326 size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize;
1328 pkc->cpy = GNUNET_malloc (size);
1329 pkc->cpy->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
1330 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
1333 pkc->cpy->purpose.purpose = htonl(GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK);
1334 pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
1335 GNUNET_SCHEDULER_add_continuation (h->sched,
1339 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1344 * Context for the SKS publication.
1346 struct PublishSksContext
1350 * Global FS context.
1352 struct GNUNET_FS_Uri *uri;
1355 * Handle to the datastore.
1357 struct GNUNET_DATASTORE_Handle *dsh;
1360 * Function to call once we're done.
1362 GNUNET_FS_PublishContinuation cont;
1373 * Function called by the datastore API with
1374 * the result from the PUT (SBlock) request.
1376 * @param cls closure of type "struct PublishSksContext*"
1377 * @param success GNUNET_OK on success
1378 * @param msg error message (or NULL)
1381 sb_put_cont (void *cls,
1385 struct PublishSksContext *psc = cls;
1387 if (NULL != psc->dsh)
1388 GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
1389 if (GNUNET_OK != success)
1390 psc->cont (psc->cont_cls,
1394 psc->cont (psc->cont_cls,
1397 GNUNET_FS_uri_destroy (psc->uri);
1403 * Publish an SBlock on GNUnet.
1405 * @param h handle to the file sharing subsystem
1406 * @param namespace namespace to publish in
1407 * @param identifier identifier to use
1408 * @param update update identifier to use
1409 * @param meta metadata to use
1410 * @param uri URI to refer to in the SBlock
1411 * @param expirationTime when the SBlock expires
1412 * @param anonymity anonymity level for the SBlock
1413 * @param priority priority for the SBlock
1414 * @param options publication options
1415 * @param cont continuation
1416 * @param cont_cls closure for cont
1419 GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
1420 struct GNUNET_FS_Namespace *namespace,
1421 const char *identifier,
1423 struct GNUNET_CONTAINER_MetaData *meta,
1424 struct GNUNET_FS_Uri *uri,
1425 struct GNUNET_TIME_Absolute expirationTime,
1426 unsigned int anonymity,
1427 unsigned int priority,
1428 enum GNUNET_FS_PublishOptions options,
1429 GNUNET_FS_PublishContinuation cont,
1432 struct PublishSksContext *psc;
1433 struct GNUNET_CRYPTO_AesSessionKey sk;
1434 struct GNUNET_CRYPTO_AesInitializationVector iv;
1435 struct GNUNET_FS_Uri *sks_uri;
1443 struct SBlock *sb_enc;
1445 GNUNET_HashCode key; /* hash of thisId = key */
1446 GNUNET_HashCode id; /* hash of hc = identifier */
1448 uris = GNUNET_FS_uri_to_string (uri);
1449 slen = strlen (uris) + 1;
1450 idlen = strlen (identifier);
1453 nidlen = strlen (update) + 1;
1454 mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta,
1455 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1457 size = sizeof (struct SBlock) + slen + nidlen + mdsize;
1458 if (size > MAX_SBLOCK_SIZE)
1460 size = MAX_SBLOCK_SIZE;
1461 mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
1463 sb = GNUNET_malloc (sizeof (struct SBlock) + size);
1464 dest = (char *) &sb[1];
1465 memcpy (dest, update, nidlen);
1467 memcpy (dest, uris, slen);
1469 mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
1472 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1480 _("Internal error."));
1483 size = sizeof (struct SBlock) + mdsize + slen + nidlen;
1484 sb_enc = GNUNET_malloc (sizeof (struct SBlock) + size);
1485 GNUNET_CRYPTO_hash (identifier, idlen, &key);
1486 GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
1487 sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
1488 sks_uri->type = sks;
1489 GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
1490 GNUNET_CRYPTO_hash (&sb_enc->subspace,
1491 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1492 &sks_uri->data.sks.namespace);
1493 sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
1494 GNUNET_CRYPTO_hash_xor (&id,
1495 &sks_uri->data.sks.namespace,
1496 &sb_enc->identifier);
1497 GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
1498 GNUNET_CRYPTO_aes_encrypt (&sb[1],
1499 size - sizeof (struct SBlock),
1504 sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
1505 sb_enc->purpose.size = htonl(slen + mdsize + nidlen
1506 + sizeof(struct SBlock)
1507 - sizeof(struct GNUNET_CRYPTO_RsaSignature));
1508 GNUNET_assert (GNUNET_OK ==
1509 GNUNET_CRYPTO_rsa_sign (namespace->key,
1511 &sb_enc->signature));
1512 psc = GNUNET_malloc (sizeof(struct PublishSksContext));
1515 psc->cont_cls = cont_cls;
1516 if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1518 GNUNET_free (sb_enc);
1524 psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
1525 if (NULL == psc->dsh)
1527 GNUNET_free (sb_enc);
1530 _("Failed to connect to datastore."));
1534 GNUNET_DATASTORE_put (psc->dsh,
1539 GNUNET_DATASTORE_BLOCKTYPE_SBLOCK,
1543 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1546 GNUNET_free (sb_enc);
1550 /* end of fs_publish.c */