From: Christian Grothoff Date: Sat, 18 Feb 2012 19:03:26 +0000 (+0000) Subject: make all (?) asynchronously operating FS operations actually cancel-able X-Git-Tag: initial-import-from-subversion-38251~14814 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=c456c5bb7f9b95d1800ad6e2892a77f40a08493e;p=oweals%2Fgnunet.git make all (?) asynchronously operating FS operations actually cancel-able --- diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am index c4db16fb0..d9b0fbadd 100644 --- a/src/fs/Makefile.am +++ b/src/fs/Makefile.am @@ -33,8 +33,10 @@ libgnunetfs_la_SOURCES = \ fs_getopt.c \ fs_list_indexed.c \ fs_publish.c \ + fs_publish_ksk.c \ fs_misc.c \ fs_namespace.c \ + fs_namespace_advertise.c \ fs_search.c \ fs_sharetree.c \ fs_tree.c fs_tree.h \ diff --git a/src/fs/fs_api.h b/src/fs/fs_api.h index 42daa7bc2..de66ac661 100644 --- a/src/fs/fs_api.h +++ b/src/fs/fs_api.h @@ -1160,6 +1160,18 @@ struct GNUNET_FS_PublishContext */ struct GNUNET_DATASTORE_QueueEntry *qre; + /** + * Context for SKS publishing operation that is part of this publishing operation + * (NULL if not active). + */ + struct GNUNET_FS_PublishSksContext *sks_pc; + + /** + * Context for KSK publishing operation that is part of this publishing operation + * (NULL if not active). + */ + struct GNUNET_FS_PublishKskContext *ksk_pc; + /** * ID of the task performing the upload. NO_TASK if the upload has * completed. @@ -1177,17 +1189,6 @@ struct GNUNET_FS_PublishContext */ uint32_t reserve_entries; - /** - * Typically GNUNET_NO. Set to GNUNET_YES if "upload_task" is - * GNUNET_SCHEDULER_NO_TASK and we're waiting for a response from - * the datastore service (in which case this struct must not be - * freed until we have that response). If someone tries to stop the - * download for good during this period, "in_network_wait" is set to - * GNUNET_SYSERR which will cause the struct to be destroyed right - * after we have the reply (or timeout) from the datastore service. - */ - int in_network_wait; - /** * Options for publishing. */ diff --git a/src/fs/fs_list_indexed.c b/src/fs/fs_list_indexed.c index 0896de347..784c9881a 100644 --- a/src/fs/fs_list_indexed.c +++ b/src/fs/fs_list_indexed.c @@ -34,7 +34,7 @@ /** * Context for "GNUNET_FS_get_indexed_files". */ -struct GetIndexedContext +struct GNUNET_FS_GetIndexedContext { /** * Handle to global FS context. @@ -72,13 +72,13 @@ struct GetIndexedContext * Function called on each response from the FS * service with information about indexed files. * - * @param cls closure (of type "struct GetIndexedContext*") + * @param cls closure (of type "struct GNUNET_FS_GetIndexedContext*") * @param msg message with indexing information */ static void handle_index_info (void *cls, const struct GNUNET_MessageHeader *msg) { - struct GetIndexedContext *gic = cls; + struct GNUNET_FS_GetIndexedContext *gic = cls; const struct IndexInfoMessage *iim; uint16_t msize; const char *filename; @@ -89,19 +89,15 @@ handle_index_info (void *cls, const struct GNUNET_MessageHeader *msg) _ ("Failed to receive response for `%s' request from `%s' service.\n"), "GET_INDEXED", "fs"); - GNUNET_SCHEDULER_add_continuation (gic->cont, gic->cont_cls, - GNUNET_SCHEDULER_REASON_TIMEOUT); - GNUNET_CLIENT_disconnect (gic->client, GNUNET_NO); - GNUNET_free (gic); + (void) gic->iterator (gic->iterator_cls, NULL, NULL); + GNUNET_FS_get_indexed_files_cancel (gic); return; } if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END) { /* normal end-of-list */ - GNUNET_SCHEDULER_add_continuation (gic->cont, gic->cont_cls, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - GNUNET_CLIENT_disconnect (gic->client, GNUNET_NO); - GNUNET_free (gic); + (void) gic->iterator (gic->iterator_cls, NULL, NULL); + GNUNET_FS_get_indexed_files_cancel (gic); return; } msize = ntohs (msg->size); @@ -116,18 +112,13 @@ handle_index_info (void *cls, const struct GNUNET_MessageHeader *msg) _ ("Failed to receive valid response for `%s' request from `%s' service.\n"), "GET_INDEXED", "fs"); - GNUNET_SCHEDULER_add_continuation (gic->cont, gic->cont_cls, - GNUNET_SCHEDULER_REASON_TIMEOUT); - GNUNET_CLIENT_disconnect (gic->client, GNUNET_NO); - GNUNET_free (gic); + (void) gic->iterator (gic->iterator_cls, NULL, NULL); + GNUNET_FS_get_indexed_files_cancel (gic); return; } if (GNUNET_OK != gic->iterator (gic->iterator_cls, filename, &iim->file_id)) { - GNUNET_SCHEDULER_add_continuation (gic->cont, gic->cont_cls, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - GNUNET_CLIENT_disconnect (gic->client, GNUNET_NO); - GNUNET_free (gic); + GNUNET_FS_get_indexed_files_cancel (gic); return; } /* get more */ @@ -142,19 +133,15 @@ handle_index_info (void *cls, const struct GNUNET_MessageHeader *msg) * @param h handle to the file sharing subsystem * @param iterator function to call on each indexed file * @param iterator_cls closure for iterator - * @param cont continuation to call when done; - * reason should be "TIMEOUT" (on - * error) or "PREREQ_DONE" (on success) - * @param cont_cls closure for cont + * @return NULL on error ('iter' is not called) */ -void +struct GNUNET_FS_GetIndexedContext * GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, GNUNET_FS_IndexedFileProcessor iterator, - void *iterator_cls, GNUNET_SCHEDULER_Task cont, - void *cont_cls) + void *iterator_cls) { struct GNUNET_CLIENT_Connection *client; - struct GetIndexedContext *gic; + struct GNUNET_FS_GetIndexedContext *gic; struct GNUNET_MessageHeader msg; client = GNUNET_CLIENT_connect ("fs", h->cfg); @@ -162,18 +149,13 @@ GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to not connect to `%s' service.\n"), "fs"); - GNUNET_SCHEDULER_add_continuation (cont, cont_cls, - GNUNET_SCHEDULER_REASON_TIMEOUT); - return; + return NULL; } - - gic = GNUNET_malloc (sizeof (struct GetIndexedContext)); + gic = GNUNET_malloc (sizeof (struct GNUNET_FS_GetIndexedContext)); gic->h = h; gic->client = client; gic->iterator = iterator; gic->iterator_cls = iterator_cls; - gic->cont = cont; - gic->cont_cls = cont_cls; msg.size = htons (sizeof (struct GNUNET_MessageHeader)); msg.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET); GNUNET_assert (GNUNET_OK == @@ -182,6 +164,21 @@ GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, GNUNET_YES, &handle_index_info, gic)); + return gic; +} + + +/** + * Cancel iteration over all indexed files. + * + * @param gic operation to cancel + */ +void +GNUNET_FS_get_indexed_files_cancel (struct GNUNET_FS_GetIndexedContext *gic) +{ + GNUNET_CLIENT_disconnect (gic->client, GNUNET_NO); + GNUNET_free (gic); } + /* end of fs_list_indexed.c */ diff --git a/src/fs/fs_namespace.c b/src/fs/fs_namespace.c index 9cb8cd5a4..e7cf38800 100644 --- a/src/fs/fs_namespace.c +++ b/src/fs/fs_namespace.c @@ -30,19 +30,12 @@ #include "gnunet_fs_service.h" #include "fs_api.h" -#define DEBUG_NAMESPACE GNUNET_EXTRA_LOGGING - /** * Maximum legal size for an sblock. */ #define MAX_SBLOCK_SIZE (60 * 1024) -/** - * Maximum legal size for an nblock. - */ -#define MAX_NBLOCK_SIZE (60 * 1024) - /** * Return the name of the directory in which we store @@ -233,253 +226,6 @@ END: } -/** - * Context for advertising a namespace. - */ -struct AdvertisementContext -{ - /** - * Function to call with the result. - */ - GNUNET_FS_PublishContinuation cont; - - /** - * Closure for cont. - */ - void *cont_cls; - - /** - * Datastore handle. - */ - struct GNUNET_DATASTORE_Handle *dsh; - - /** - * Our KSK URI. - */ - struct GNUNET_FS_Uri *ksk_uri; - - /** - * Plaintext. - */ - char *pt; - - /** - * NBlock to sign and store. - */ - struct NBlock *nb; - - /** - * The namespace. - */ - struct GNUNET_FS_Namespace *ns; - - /** - * Block options. - */ - struct GNUNET_FS_BlockOptions bo; - - /** - * Number of bytes of plaintext. - */ - size_t pt_size; - - /** - * Current keyword offset. - */ - unsigned int pos; -}; - - -/** - * Disconnect from the datastore. - * - * @param cls datastore handle - * @param tc scheduler context - */ -static void -do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_DATASTORE_Handle *dsh = cls; - - GNUNET_DATASTORE_disconnect (dsh, GNUNET_NO); -} - - -/** - * Continuation called to notify client about result of the - * operation. - * - * @param cls closure (our struct AdvertismentContext) - * @param success GNUNET_SYSERR on failure - * @param min_expiration minimum expiration time required for content to be stored - * @param msg NULL on success, otherwise an error message - */ -static void -advertisement_cont (void *cls, int success, - struct GNUNET_TIME_Absolute min_expiration, - const char *msg) -{ - struct AdvertisementContext *ac = cls; - const char *keyword; - GNUNET_HashCode key; - GNUNET_HashCode query; - struct GNUNET_CRYPTO_AesSessionKey skey; - struct GNUNET_CRYPTO_AesInitializationVector iv; - struct GNUNET_CRYPTO_RsaPrivateKey *pk; - - if (GNUNET_OK != success) - { - /* error! */ - GNUNET_SCHEDULER_add_continuation (&do_disconnect, ac->dsh, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - if (msg == NULL) - { - GNUNET_break (0); - msg = _("Unknown error"); - } - if (ac->cont != NULL) - ac->cont (ac->cont_cls, NULL, msg); - GNUNET_FS_uri_destroy (ac->ksk_uri); - GNUNET_free (ac->pt); - GNUNET_free (ac->nb); - GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO); - GNUNET_free (ac); - return; - } - if (ac->pos == ac->ksk_uri->data.ksk.keywordCount) - { - /* done! */ - GNUNET_SCHEDULER_add_continuation (&do_disconnect, ac->dsh, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - if (ac->cont != NULL) - ac->cont (ac->cont_cls, ac->ksk_uri, NULL); - GNUNET_FS_uri_destroy (ac->ksk_uri); - GNUNET_free (ac->pt); - GNUNET_free (ac->nb); - GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO); - GNUNET_free (ac); - return; - } - keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++]; - /* first character of keyword indicates if it is - * mandatory or not -- ignore for hashing */ - GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); - GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); - GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]); - GNUNET_break (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose, - &ac->nb->ns_signature)); - pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); - GNUNET_assert (pk != NULL); - GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace); - GNUNET_CRYPTO_hash (&ac->nb->keyspace, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &query); - GNUNET_break (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose, - &ac->nb->ksk_signature)); - GNUNET_CRYPTO_rsa_key_free (pk); - GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ , - &query, ac->pt_size + sizeof (struct NBlock), ac->nb, - GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority, - ac->bo.anonymity_level, ac->bo.replication_level, - ac->bo.expiration_time, -2, 1, - GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont, - ac); -} - - -/** - * Publish an advertismement for a namespace. - * - * @param h handle to the file sharing subsystem - * @param ksk_uri keywords to use for advertisment - * @param namespace handle for the namespace that should be advertised - * @param meta meta-data for the namespace advertisement - * @param bo block options - * @param rootEntry name of the root of the namespace - * @param cont continuation - * @param cont_cls closure for cont - */ -void -GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, - struct GNUNET_FS_Uri *ksk_uri, - struct GNUNET_FS_Namespace *namespace, - const struct GNUNET_CONTAINER_MetaData *meta, - const struct GNUNET_FS_BlockOptions *bo, - const char *rootEntry, - GNUNET_FS_PublishContinuation cont, - void *cont_cls) -{ - size_t reslen; - size_t size; - ssize_t mdsize; - struct NBlock *nb; - char *mdst; - struct GNUNET_DATASTORE_Handle *dsh; - struct AdvertisementContext *ctx; - char *pt; - - /* create advertisements */ - mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); - if (-1 == mdsize) - { - cont (cont_cls, NULL, _("Failed to serialize meta data")); - return; - } - reslen = strlen (rootEntry) + 1; - size = mdsize + sizeof (struct NBlock) + reslen; - if (size > MAX_NBLOCK_SIZE) - { - size = MAX_NBLOCK_SIZE; - mdsize = size - sizeof (struct NBlock) - reslen; - } - - pt = GNUNET_malloc (mdsize + reslen); - memcpy (pt, rootEntry, reslen); - mdst = &pt[reslen]; - mdsize = - GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize, - GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); - if (mdsize == -1) - { - GNUNET_break (0); - GNUNET_free (pt); - cont (cont_cls, NULL, _("Failed to serialize meta data")); - return; - } - size = mdsize + sizeof (struct NBlock) + reslen; - nb = GNUNET_malloc (size); - GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace); - nb->ns_purpose.size = - htonl (mdsize + reslen + - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK); - nb->ksk_purpose.size = - htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); - nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG); - dsh = GNUNET_DATASTORE_connect (h->cfg); - if (NULL == dsh) - { - GNUNET_free (nb); - GNUNET_free (pt); - cont (cont_cls, NULL, _("Failed to connect to datastore service")); - return; - } - ctx = GNUNET_malloc (sizeof (struct AdvertisementContext)); - ctx->cont = cont; - ctx->cont_cls = cont_cls; - ctx->dsh = dsh; - ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); - ctx->nb = nb; - ctx->pt = pt; - ctx->pt_size = mdsize + reslen; - ctx->ns = namespace; - ctx->ns->rc++; - ctx->bo = *bo; - advertisement_cont (ctx, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); -} /** @@ -557,26 +303,25 @@ GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, int freeze) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", namespace->filename); } - if (0 == namespace->rc) + if (0 != namespace->rc) + return GNUNET_OK; + GNUNET_CRYPTO_rsa_key_free (namespace->key); + GNUNET_free (namespace->filename); + GNUNET_free (namespace->name); + for (i = 0; i < namespace->update_node_count; i++) { - GNUNET_CRYPTO_rsa_key_free (namespace->key); - GNUNET_free (namespace->filename); - GNUNET_free (namespace->name); - for (i = 0; i < namespace->update_node_count; i++) - { - nsn = namespace->update_nodes[i]; - GNUNET_CONTAINER_meta_data_destroy (nsn->md); - GNUNET_FS_uri_destroy (nsn->uri); - GNUNET_free (nsn->id); - GNUNET_free (nsn->update); - GNUNET_free (nsn); - } - GNUNET_array_grow (namespace->update_nodes, namespace->update_node_count, - 0); - if (namespace->update_map != NULL) - GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map); - GNUNET_free (namespace); - } + nsn = namespace->update_nodes[i]; + GNUNET_CONTAINER_meta_data_destroy (nsn->md); + GNUNET_FS_uri_destroy (nsn->uri); + GNUNET_free (nsn->id); + GNUNET_free (nsn->update); + GNUNET_free (nsn); + } + GNUNET_array_grow (namespace->update_nodes, namespace->update_node_count, + 0); + if (namespace->update_map != NULL) + GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map); + GNUNET_free (namespace); return GNUNET_OK; } @@ -666,12 +411,10 @@ GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h, } - - /** * Context for the SKS publication. */ -struct PublishSksContext +struct GNUNET_FS_PublishSksContext { /** @@ -705,6 +448,10 @@ struct PublishSksContext */ void *cont_cls; + /** + * Handle for our datastore request. + */ + struct GNUNET_DATASTORE_QueueEntry *dqe; }; @@ -712,7 +459,7 @@ struct PublishSksContext * Function called by the datastore API with * the result from the PUT (SBlock) request. * - * @param cls closure of type "struct PublishSksContext*" + * @param cls closure of type "struct GNUNET_FS_PublishSksContext*" * @param success GNUNET_OK on success * @param min_expiration minimum expiration time required for content to be stored * @param msg error message (or NULL) @@ -722,54 +469,39 @@ sb_put_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { - struct PublishSksContext *psc = cls; + struct GNUNET_FS_PublishSksContext *psc = cls; GNUNET_HashCode hc; - if (NULL != psc->dsh) - { - GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO); - psc->dsh = NULL; - } + psc->dqe = NULL; if (GNUNET_OK != success) { - if (psc->cont != NULL) + if (NULL != psc->cont) psc->cont (psc->cont_cls, NULL, msg); + GNUNET_FS_publish_sks_cancel (psc); + return; } - else + if (NULL != psc->nsn) { - if (psc->nsn != NULL) + /* FIXME: this can be done much more + * efficiently by simply appending to the + * file and overwriting the 4-byte header */ + if (psc->namespace->update_nodes == NULL) + read_update_information_graph (psc->namespace); + GNUNET_array_append (psc->namespace->update_nodes, + psc->namespace->update_node_count, psc->nsn); + if (psc->namespace->update_map != NULL) { - /* FIXME: this can be done much more - * efficiently by simply appending to the - * file and overwriting the 4-byte header */ - if (psc->namespace->update_nodes == NULL) - read_update_information_graph (psc->namespace); - GNUNET_array_append (psc->namespace->update_nodes, - psc->namespace->update_node_count, psc->nsn); - if (psc->namespace->update_map != NULL) - { - GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc); - GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map, &hc, - psc->nsn, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - } - psc->nsn = NULL; - write_update_information_graph (psc->namespace); + GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc); + GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map, &hc, + psc->nsn, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } - if (psc->cont != NULL) - psc->cont (psc->cont_cls, psc->uri, NULL); - } - GNUNET_FS_namespace_delete (psc->namespace, GNUNET_NO); - GNUNET_FS_uri_destroy (psc->uri); - if (psc->nsn != NULL) - { - GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md); - GNUNET_FS_uri_destroy (psc->nsn->uri); - GNUNET_free (psc->nsn->id); - GNUNET_free (psc->nsn->update); - GNUNET_free (psc->nsn); + psc->nsn = NULL; + write_update_information_graph (psc->namespace); } - GNUNET_free (psc); + if (NULL != psc->cont) + psc->cont (psc->cont_cls, psc->uri, NULL); + GNUNET_FS_publish_sks_cancel (psc); } @@ -786,8 +518,9 @@ sb_put_cont (void *cls, int success, * @param options publication options * @param cont continuation * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) */ -void +struct GNUNET_FS_PublishSksContext * GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, struct GNUNET_FS_Namespace *namespace, const char *identifier, const char *update, @@ -797,7 +530,7 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, enum GNUNET_FS_PublishOptions options, GNUNET_FS_PublishContinuation cont, void *cont_cls) { - struct PublishSksContext *psc; + struct GNUNET_FS_PublishSksContext *psc; struct GNUNET_CRYPTO_AesSessionKey sk; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_FS_Uri *sks_uri; @@ -851,8 +584,9 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, { GNUNET_break (0); GNUNET_free (sb); - cont (cont_cls, NULL, _("Internal error.")); - return; + if (NULL != cont) + cont (cont_cls, NULL, _("Internal error.")); + return NULL; } size = sizeof (struct SBlock) + mdsize + slen + nidlen; sb_enc = GNUNET_malloc (size); @@ -877,18 +611,17 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (namespace->key, &sb_enc->purpose, &sb_enc->signature)); - psc = GNUNET_malloc (sizeof (struct PublishSksContext)); + psc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishSksContext)); psc->uri = sks_uri; psc->cont = cont; - psc->namespace = namespace; - namespace->rc++; + psc->namespace = GNUNET_FS_namespace_dup (namespace); psc->cont_cls = cont_cls; if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) { GNUNET_free (sb_enc); GNUNET_free (sb); sb_put_cont (psc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); - return; + return NULL; } psc->dsh = GNUNET_DATASTORE_connect (h->cfg); if (NULL == psc->dsh) @@ -896,7 +629,7 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, GNUNET_free (sb_enc); GNUNET_free (sb); sb_put_cont (psc, GNUNET_NO, GNUNET_TIME_UNIT_ZERO_ABS, _("Failed to connect to datastore.")); - return; + return NULL; } GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace, &id, &query); if (NULL != update) @@ -907,13 +640,46 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta); psc->nsn->uri = GNUNET_FS_uri_dup (uri); } - GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc, - GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority, - bo->anonymity_level, bo->replication_level, - bo->expiration_time, -2, 1, - GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc); + psc->dqe = GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc, + GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority, + bo->anonymity_level, bo->replication_level, + bo->expiration_time, -2, 1, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc); GNUNET_free (sb); GNUNET_free (sb_enc); + return psc; +} + + +/** + * Abort the SKS publishing operation. + * + * @param sc context of the operation to abort. + */ +void +GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc) +{ + if (NULL != psc->dqe) + { + GNUNET_DATASTORE_cancel (psc->dqe); + psc->dqe = NULL; + } + if (NULL != psc->dsh) + { + GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO); + psc->dsh = NULL; + } + GNUNET_FS_namespace_delete (psc->namespace, GNUNET_NO); + GNUNET_FS_uri_destroy (psc->uri); + if (NULL != psc->nsn) + { + GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md); + GNUNET_FS_uri_destroy (psc->nsn->uri); + GNUNET_free (psc->nsn->id); + GNUNET_free (psc->nsn->update); + GNUNET_free (psc->nsn); + } + GNUNET_free (psc); } @@ -1081,10 +847,8 @@ GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, read_update_information_graph (namespace); if (namespace->update_nodes == NULL) { -#if DEBUG_NAMESPACE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No updateable nodes found for ID `%s'\n", next_id); -#endif return; /* no nodes */ } if (namespace->update_map == NULL) @@ -1111,10 +875,8 @@ GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, &process_update_node, &pc); return; } -#if DEBUG_NAMESPACE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calculating TREEs to find roots of update trees\n"); -#endif /* Find heads of TREEs in update graph */ nug = ++namespace->nug_gen; fc.tree_array = NULL; @@ -1125,10 +887,8 @@ GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, nsn = namespace->update_nodes[i]; if (nsn->nug == nug) { -#if DEBUG_NAMESPACE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id, nsn->nug); -#endif continue; /* already placed in TREE */ } GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc); @@ -1156,11 +916,9 @@ GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn); nsn->tree_id = fc.id; } -#if DEBUG_NAMESPACE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting new TREE %u with node `%s'\n", nsn->tree_id, nsn->id); -#endif /* put all nodes with same identifier into this TREE */ GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc); fc.id = nsn->tree_id; @@ -1175,28 +933,21 @@ GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, fc.tree_array[fc.id] = nsn; nsn->tree_id = fc.id; } -#if DEBUG_NAMESPACE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id, fc.id); -#endif } for (i = 0; i < fc.tree_array_size; i++) { nsn = fc.tree_array[i]; if (NULL != nsn) { -#if DEBUG_NAMESPACE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Root of TREE %u is node `%s'\n", i, nsn->id); -#endif - ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update); } } GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0); -#if DEBUG_NAMESPACE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n"); -#endif } diff --git a/src/fs/fs_namespace_advertise.c b/src/fs/fs_namespace_advertise.c new file mode 100644 index 000000000..60b4de095 --- /dev/null +++ b/src/fs/fs_namespace_advertise.c @@ -0,0 +1,323 @@ +/* + This file is part of GNUnet + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_namespace_advertise.c + * @brief advertise namespaces (creating NBlocks) + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" + + +/** + * Maximum legal size for an nblock. + */ +#define MAX_NBLOCK_SIZE (60 * 1024) + + +/** + * Context for advertising a namespace. + */ +struct GNUNET_FS_AdvertisementContext +{ + /** + * Function to call with the result. + */ + GNUNET_FS_PublishContinuation cont; + + /** + * Closure for cont. + */ + void *cont_cls; + + /** + * Datastore handle. + */ + struct GNUNET_DATASTORE_Handle *dsh; + + /** + * Our KSK URI. + */ + struct GNUNET_FS_Uri *ksk_uri; + + /** + * Plaintext. + */ + char *pt; + + /** + * NBlock to sign and store. + */ + struct NBlock *nb; + + /** + * The namespace. + */ + struct GNUNET_FS_Namespace *ns; + + /** + * Current datastore queue entry for advertising. + */ + struct GNUNET_DATASTORE_QueueEntry *dqe; + + /** + * Block options. + */ + struct GNUNET_FS_BlockOptions bo; + + /** + * Number of bytes of plaintext. + */ + size_t pt_size; + + /** + * Current keyword offset. + */ + unsigned int pos; +}; + + +// FIXME: I see no good reason why this should need to be done +// in a new task (anymore). Integrate with 'cancel' function below? +/** + * Disconnect from the datastore. + * + * @param cls datastore handle + * @param tc scheduler context + */ +static void +do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_DATASTORE_Handle *dsh = cls; + + GNUNET_DATASTORE_disconnect (dsh, GNUNET_NO); +} + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure (our struct GNUNET_FS_AdvertismentContext) + * @param success GNUNET_SYSERR on failure + * @param min_expiration minimum expiration time required for content to be stored + * @param msg NULL on success, otherwise an error message + */ +static void +advertisement_cont (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_AdvertisementContext *ac = cls; + const char *keyword; + GNUNET_HashCode key; + GNUNET_HashCode query; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_CRYPTO_RsaPrivateKey *pk; + + ac->dqe = NULL; + if (GNUNET_SYSERR == success) + { + /* error! */ + (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); + ac->dsh = NULL; + if (msg == NULL) + { + GNUNET_break (0); + msg = _("Unknown error"); + } + if (ac->cont != NULL) + { + ac->cont (ac->cont_cls, NULL, msg); + ac->cont = NULL; + } + GNUNET_FS_namespace_advertise_cancel (ac); + return; + } + if (ac->pos == ac->ksk_uri->data.ksk.keywordCount) + { + /* done! */ + (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); + ac->dsh = NULL; + if (ac->cont != NULL) + { + ac->cont (ac->cont_cls, ac->ksk_uri, NULL); + ac->cont = NULL; + } + GNUNET_FS_namespace_advertise_cancel (ac); + return; + } + keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++]; + /* first character of keyword indicates if it is + * mandatory or not -- ignore for hashing */ + GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); + GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); + GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]); + GNUNET_break (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose, + &ac->nb->ns_signature)); + pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); + GNUNET_assert (pk != NULL); + GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace); + GNUNET_CRYPTO_hash (&ac->nb->keyspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &query); + GNUNET_break (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose, + &ac->nb->ksk_signature)); + GNUNET_CRYPTO_rsa_key_free (pk); + ac->dqe = GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ , + &query, ac->pt_size + sizeof (struct NBlock), ac->nb, + GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority, + ac->bo.anonymity_level, ac->bo.replication_level, + ac->bo.expiration_time, -2, 1, + GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont, + ac); +} + + +/** + * Publish an advertismement for a namespace. + * + * @param h handle to the file sharing subsystem + * @param ksk_uri keywords to use for advertisment + * @param namespace handle for the namespace that should be advertised + * @param meta meta-data for the namespace advertisement + * @param bo block options + * @param rootEntry name of the root of the namespace + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' is still called) + */ +struct GNUNET_FS_AdvertisementContext * +GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, + struct GNUNET_FS_Uri *ksk_uri, + struct GNUNET_FS_Namespace *namespace, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_BlockOptions *bo, + const char *rootEntry, + GNUNET_FS_PublishContinuation cont, + void *cont_cls) +{ + size_t reslen; + size_t size; + ssize_t mdsize; + struct NBlock *nb; + char *mdst; + struct GNUNET_DATASTORE_Handle *dsh; + struct GNUNET_FS_AdvertisementContext *ctx; + char *pt; + + /* create advertisements */ + mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); + if (-1 == mdsize) + { + cont (cont_cls, NULL, _("Failed to serialize meta data")); + return NULL; + } + reslen = strlen (rootEntry) + 1; + size = mdsize + sizeof (struct NBlock) + reslen; + if (size > MAX_NBLOCK_SIZE) + { + size = MAX_NBLOCK_SIZE; + mdsize = size - sizeof (struct NBlock) - reslen; + } + + pt = GNUNET_malloc (mdsize + reslen); + memcpy (pt, rootEntry, reslen); + mdst = &pt[reslen]; + mdsize = + GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + if (-1 == mdsize) + { + GNUNET_break (0); + GNUNET_free (pt); + cont (cont_cls, NULL, _("Failed to serialize meta data")); + return NULL; + } + size = mdsize + sizeof (struct NBlock) + reslen; + nb = GNUNET_malloc (size); + GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace); + nb->ns_purpose.size = + htonl (mdsize + reslen + + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK); + nb->ksk_purpose.size = + htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); + nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG); + dsh = GNUNET_DATASTORE_connect (h->cfg); + if (NULL == dsh) + { + GNUNET_free (nb); + GNUNET_free (pt); + cont (cont_cls, NULL, _("Failed to connect to datastore service")); + return NULL; + } + ctx = GNUNET_malloc (sizeof (struct GNUNET_FS_AdvertisementContext)); + ctx->cont = cont; + ctx->cont_cls = cont_cls; + ctx->dsh = dsh; + ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); + ctx->nb = nb; + ctx->pt = pt; + ctx->pt_size = mdsize + reslen; + ctx->ns = namespace; + ctx->ns->rc++; + ctx->bo = *bo; + advertisement_cont (ctx, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); + return ctx; +} + + +/** + * Abort the namespace advertisement operation. + * + * @param pkc context of the operation to abort. + */ +void +GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac) +{ + if (NULL != ac->dqe) + { + GNUNET_DATASTORE_cancel (ac->dqe); + ac->dqe = NULL; + } + if (NULL != ac->dsh) + { + GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO); + ac->dsh = NULL; + } + GNUNET_FS_uri_destroy (ac->ksk_uri); + GNUNET_free (ac->pt); + GNUNET_free (ac->nb); + GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO); + GNUNET_free (ac); +} + + +/* end of fs_namespace_advertise.c */ diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c index 444128016..134dd21e4 100644 --- a/src/fs/fs_publish.c +++ b/src/fs/fs_publish.c @@ -34,13 +34,6 @@ #include "fs_api.h" #include "fs_tree.h" -#define DEBUG_PUBLISH GNUNET_EXTRA_LOGGING - -/** - * Maximum legal size for a kblock. - */ -#define MAX_KBLOCK_SIZE (60 * 1024) - /** * Fill in all of the generic fields for @@ -78,17 +71,12 @@ GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, /** * Cleanup the publish context, we're done with it. * - * @param cls struct to clean up after - * @param tc scheduler context + * @param pc struct to clean up */ static void -publish_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +publish_cleanup (struct GNUNET_FS_PublishContext *pc) { - struct GNUNET_FS_PublishContext *pc = cls; - -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up publish context (done!)\n"); -#endif if (pc->fhc != NULL) { GNUNET_CRYPTO_hash_file_cancel (pc->fhc); @@ -136,15 +124,6 @@ ds_put_cont (void *cls, int success, struct GNUNET_FS_ProgressInfo pi; pc->qre = NULL; - if (GNUNET_SYSERR == pc->in_network_wait) - { - /* we were aborted in the meantime, finish shutdown! */ - GNUNET_SCHEDULER_add_continuation (&publish_cleanup, pc, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - return; - } - GNUNET_assert (GNUNET_YES == pc->in_network_wait); - pc->in_network_wait = GNUNET_NO; if (GNUNET_SYSERR == success) { GNUNET_asprintf (&pc->fi_pos->emsg, _("Publishing failed: %s"), msg); @@ -238,9 +217,7 @@ finish_release_reserve (void *cls, int success, struct GNUNET_FS_PublishContext *pc = cls; pc->qre = NULL; -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Releasing reserve done!\n"); -#endif signal_publish_completion (pc->fi, pc); pc->all_done = GNUNET_YES; GNUNET_FS_publish_sync_ (pc); @@ -261,6 +238,7 @@ publish_sblocks_cont (void *cls, const struct GNUNET_FS_Uri *uri, { struct GNUNET_FS_PublishContext *pc = cls; + pc->sks_pc = NULL; if (NULL != emsg) { signal_publish_error (pc->fi, pc, emsg); @@ -292,9 +270,9 @@ static void publish_sblock (struct GNUNET_FS_PublishContext *pc) { if (NULL != pc->namespace) - GNUNET_FS_publish_sks (pc->h, pc->namespace, pc->nid, pc->nuid, - pc->fi->meta, pc->fi->chk_uri, &pc->fi->bo, - pc->options, &publish_sblocks_cont, pc); + pc->sks_pc = GNUNET_FS_publish_sks (pc->h, pc->namespace, pc->nid, pc->nuid, + pc->fi->meta, pc->fi->chk_uri, &pc->fi->bo, + pc->options, &publish_sblocks_cont, pc); else publish_sblocks_cont (pc, NULL, NULL); } @@ -316,25 +294,22 @@ publish_kblocks_cont (void *cls, const struct GNUNET_FS_Uri *uri, struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p = pc->fi_pos; + pc->ksk_pc = NULL; if (NULL != emsg) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error uploading KSK blocks: %s\n", emsg); -#endif signal_publish_error (p, pc, emsg); GNUNET_FS_file_information_sync_ (p); GNUNET_FS_publish_sync_ (pc); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = - GNUNET_SCHEDULER_add_with_priority - (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); + GNUNET_SCHEDULER_add_with_priority + (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); return; } -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK blocks published, moving on to next file\n"); -#endif if (NULL != p->dir) signal_publish_completion (p, pc); /* move on to next file */ @@ -415,9 +390,7 @@ encode_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) p->te = NULL; if (NULL != emsg) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error during tree walk: %s\n", emsg); -#endif GNUNET_asprintf (&p->emsg, _("Publishing failed: %s"), emsg); GNUNET_free (emsg); pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; @@ -425,9 +398,7 @@ encode_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) pi.value.publish.specifics.error.message = p->emsg; p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); } -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished with tree encoder\n"); -#endif /* final progress event */ flen = GNUNET_FS_uri_chk_get_file_size (p->chk_uri); pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; @@ -471,9 +442,7 @@ block_proc (void *cls, const struct ContentHashKey *chk, uint64_t offset, p = pc->fi_pos; if (NULL == pc->dsh) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting for datastore connection\n"); -#endif GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority @@ -481,17 +450,13 @@ block_proc (void *cls, const struct ContentHashKey *chk, uint64_t offset, return; } - GNUNET_assert (GNUNET_NO == pc->in_network_wait); - pc->in_network_wait = GNUNET_YES; if ((!p->is_directory) && (GNUNET_YES == p->data.file.do_index) && (type == GNUNET_BLOCK_TYPE_FS_DBLOCK)) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Indexing block `%s' for offset %llu with index size %u\n", GNUNET_h2s (&chk->query), (unsigned long long) offset, sizeof (struct OnDemandBlock)); -#endif odb.offset = GNUNET_htonll (offset); odb.file_id = p->data.file.file_id; GNUNET_assert (pc->qre == NULL); @@ -505,12 +470,10 @@ block_proc (void *cls, const struct ContentHashKey *chk, uint64_t offset, &ds_put_cont, pc); return; } -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing block `%s' for offset %llu with size %u\n", GNUNET_h2s (&chk->query), (unsigned long long) offset, (unsigned int) block_size); -#endif GNUNET_assert (pc->qre == NULL); pc->qre = GNUNET_DATASTORE_put (pc->dsh, (p->is_directory) ? 0 : pc->rid, @@ -573,9 +536,7 @@ publish_content (struct GNUNET_FS_PublishContext *pc) { if (p->is_directory) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating directory\n"); -#endif db = GNUNET_FS_directory_builder_create (p->meta); dirpos = p->data.dir.entries; while (NULL != dirpos) @@ -617,18 +578,14 @@ publish_content (struct GNUNET_FS_PublishContext *pc) GNUNET_FS_file_information_sync_ (p); } size = (p->is_directory) ? p->data.dir.dir_size : p->data.file.file_size; -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating tree encoder\n"); -#endif p->te = GNUNET_FS_tree_encoder_create (pc->h, size, pc, &block_reader, &block_proc, &progress_proc, &encode_cont); } -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing next block from tree\n"); -#endif GNUNET_FS_tree_encoder_next (p->te); } @@ -739,10 +696,8 @@ hash_for_index_cb (void *cls, const GNUNET_HashCode * res) publish_content (pc); return; } -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hash of indexed file `%s' is `%s'\n", p->filename, GNUNET_h2s (res)); -#endif if (0 != (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) { p->data.file.file_id = *res; @@ -779,13 +734,11 @@ hash_for_index_cb (void *cls, const GNUNET_HashCode * res) ism->device = GNUNET_htonll (dev); ism->inode = GNUNET_htonll (ino); } -#if DEBUG_PUBLISH else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Failed to get file identifiers for `%s'\n"), p->filename); } -#endif ism->file_id = *res; memcpy (&ism[1], fn, slen); GNUNET_free (fn); @@ -820,10 +773,8 @@ GNUNET_FS_publish_main_ (void *cls, p = pc->fi_pos; if (NULL == p) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing complete, now publishing SKS and KSK blocks.\n"); -#endif /* upload of entire hierarchy complete, * publish namespace entries */ GNUNET_FS_publish_sync_ (pc); @@ -841,9 +792,7 @@ GNUNET_FS_publish_main_ (void *cls, /* abort on error */ if (NULL != p->emsg) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error uploading: %s\n", p->emsg); -#endif /* error with current file, abort all * related files as well! */ while (NULL != p->dir) @@ -873,10 +822,8 @@ GNUNET_FS_publish_main_ (void *cls, /* handle completion */ if (NULL != p->chk_uri) { -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File upload complete, now publishing KSK blocks.\n"); -#endif if (0 == p->bo.anonymity_level) { /* zero anonymity, box CHK URI in LOC URI */ @@ -890,8 +837,8 @@ GNUNET_FS_publish_main_ (void *cls, /* upload of "p" complete, publish KBlocks! */ if (p->keywords != NULL) { - GNUNET_FS_publish_ksk (pc->h, p->keywords, p->meta, p->chk_uri, &p->bo, - pc->options, &publish_kblocks_cont, pc); + pc->ksk_pc = GNUNET_FS_publish_ksk (pc->h, p->keywords, p->meta, p->chk_uri, &p->bo, + pc->options, &publish_kblocks_cont, pc); } else { @@ -959,9 +906,7 @@ fip_signal_start (void *cls, struct GNUNET_FS_FileInformation *fi, pc->skip_next_fi_callback = GNUNET_NO; return GNUNET_OK; } -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting publish operation\n"); -#endif if (*do_index) { /* space for on-demand blocks */ @@ -1043,9 +988,17 @@ fip_signal_suspend (void *cls, struct GNUNET_FS_FileInformation *fi, pc->skip_next_fi_callback = GNUNET_YES; GNUNET_FS_file_information_inspect (fi, &fip_signal_suspend, pc); } -#if DEBUG_PUBLISH + if (NULL != pc->ksk_pc) + { + GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); + pc->ksk_pc = NULL; + } + if (NULL != pc->sks_pc) + { + GNUNET_FS_publish_sks_cancel (pc->sks_pc); + pc->sks_pc = NULL; + } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Suspending publish operation\n"); -#endif GNUNET_free_non_null (fi->serialization); fi->serialization = NULL; off = (fi->chk_uri == NULL) ? 0 : length; @@ -1086,7 +1039,7 @@ GNUNET_FS_publish_signal_suspend_ (void *cls) GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_suspend, pc); GNUNET_FS_end_top (pc->h, pc->top); pc->top = NULL; - publish_cleanup (pc, NULL); + publish_cleanup (pc); } @@ -1107,9 +1060,7 @@ finish_reserve (void *cls, int success, struct GNUNET_FS_PublishContext *pc = cls; pc->qre = NULL; -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reservation complete (%d)!\n", success); -#endif if ((msg != NULL) || (success <= 0)) { GNUNET_asprintf (&pc->fi->emsg, _("Insufficient space for publishing: %s"), @@ -1267,14 +1218,17 @@ GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc) struct GNUNET_FS_ProgressInfo pi; uint64_t off; -#if DEBUG_PUBLISH GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publish stop called\n"); -#endif GNUNET_FS_end_top (pc->h, pc->top); - if (NULL != pc->qre) + if (NULL != pc->ksk_pc) { - GNUNET_DATASTORE_cancel (pc->qre); - pc->qre = NULL; + GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); + pc->ksk_pc = NULL; + } + if (NULL != pc->sks_pc) + { + GNUNET_FS_publish_sks_cancel (pc->sks_pc); + pc->sks_pc = NULL; } if (GNUNET_SCHEDULER_NO_TASK != pc->upload_task) { @@ -1300,299 +1254,16 @@ GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc) GNUNET_free (pc->serialization); pc->serialization = NULL; } - if (GNUNET_YES == pc->in_network_wait) + if (NULL != pc->qre) { - pc->in_network_wait = GNUNET_SYSERR; - return; + GNUNET_DATASTORE_cancel (pc->qre); + pc->qre = NULL; } pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi, off)); - publish_cleanup (pc, NULL); + publish_cleanup (pc); } -/** - * Context for the KSK publication. - */ -struct PublishKskContext -{ - - /** - * Keywords to use. - */ - struct GNUNET_FS_Uri *ksk_uri; - - /** - * Global FS context. - */ - struct GNUNET_FS_Handle *h; - - /** - * The master block that we are sending - * (in plaintext), has "mdsize+slen" more - * bytes than the struct would suggest. - */ - struct KBlock *kb; - - /** - * Buffer of the same size as "kb" for - * the encrypted version. - */ - struct KBlock *cpy; - - /** - * Handle to the datastore, NULL if we are just - * simulating. - */ - struct GNUNET_DATASTORE_Handle *dsh; - - /** - * Handle to datastore PUT request. - */ - struct GNUNET_DATASTORE_QueueEntry *qre; - - /** - * Function to call once we're done. - */ - GNUNET_FS_PublishContinuation cont; - - /** - * Closure for cont. - */ - void *cont_cls; - - /** - * When should the KBlocks expire? - */ - struct GNUNET_FS_BlockOptions bo; - - /** - * Size of the serialized metadata. - */ - ssize_t mdsize; - - /** - * Size of the (CHK) URI as a string. - */ - size_t slen; - - /** - * Keyword that we are currently processing. - */ - unsigned int i; - -}; - - -/** - * Continuation of "GNUNET_FS_publish_ksk" that performs - * the actual publishing operation (iterating over all - * of the keywords). - * - * @param cls closure of type "struct PublishKskContext*" - * @param tc unused - */ -static void -publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Function called by the datastore API with - * the result from the PUT request. - * - * @param cls closure of type "struct PublishKskContext*" - * @param success GNUNET_OK on success - * @param min_expiration minimum expiration time required for content to be stored - * @param msg error message (or NULL) - */ -static void -kb_put_cont (void *cls, int success, - struct GNUNET_TIME_Absolute min_expiration, - const char *msg) -{ - struct PublishKskContext *pkc = cls; - - pkc->qre = NULL; - if (GNUNET_OK != success) - { -#if DEBUG_PUBLISH - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KB PUT operation complete\n"); -#endif - if (NULL != pkc->dsh) - { - GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); - pkc->dsh = NULL; - } - GNUNET_free (pkc->cpy); - GNUNET_free (pkc->kb); - pkc->cont (pkc->cont_cls, NULL, msg); - GNUNET_FS_uri_destroy (pkc->ksk_uri); - GNUNET_free (pkc); - return; - } - GNUNET_SCHEDULER_add_continuation (&publish_ksk_cont, pkc, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); -} - - -/** - * Continuation of "GNUNET_FS_publish_ksk" that performs the actual - * publishing operation (iterating over all of the keywords). - * - * @param cls closure of type "struct PublishKskContext*" - * @param tc unused - */ -static void -publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PublishKskContext *pkc = cls; - const char *keyword; - GNUNET_HashCode key; - GNUNET_HashCode query; - struct GNUNET_CRYPTO_AesSessionKey skey; - struct GNUNET_CRYPTO_AesInitializationVector iv; - struct GNUNET_CRYPTO_RsaPrivateKey *pk; - - - if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh)) - { -#if DEBUG_PUBLISH - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK PUT operation complete\n"); -#endif - if (NULL != pkc->dsh) - { - GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); - pkc->dsh = NULL; - } - GNUNET_free (pkc->cpy); - GNUNET_free (pkc->kb); - pkc->cont (pkc->cont_cls, pkc->ksk_uri, NULL); - GNUNET_FS_uri_destroy (pkc->ksk_uri); - GNUNET_free (pkc); - return; - } - keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++]; -#if DEBUG_PUBLISH - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n", - keyword); -#endif - /* first character of keyword indicates if it is - * mandatory or not -- ignore for hashing */ - GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); - GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); - GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1], pkc->slen + pkc->mdsize, &skey, &iv, - &pkc->cpy[1]); - pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); - GNUNET_assert (NULL != pk); - GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace); - GNUNET_CRYPTO_hash (&pkc->cpy->keyspace, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &query); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (pk, &pkc->cpy->purpose, - &pkc->cpy->signature)); - GNUNET_CRYPTO_rsa_key_free (pk); - pkc->qre = - GNUNET_DATASTORE_put (pkc->dsh, 0, &query, - pkc->mdsize + sizeof (struct KBlock) + pkc->slen, - pkc->cpy, GNUNET_BLOCK_TYPE_FS_KBLOCK, - pkc->bo.content_priority, pkc->bo.anonymity_level, - pkc->bo.replication_level, pkc->bo.expiration_time, - -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, - &kb_put_cont, pkc); -} - - -/** - * Publish a CHK under various keywords on GNUnet. - * - * @param h handle to the file sharing subsystem - * @param ksk_uri keywords to use - * @param meta metadata to use - * @param uri URI to refer to in the KBlock - * @param bo per-block options - * @param options publication options - * @param cont continuation - * @param cont_cls closure for cont - */ -void -GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, - const struct GNUNET_FS_Uri *ksk_uri, - const struct GNUNET_CONTAINER_MetaData *meta, - const struct GNUNET_FS_Uri *uri, - const struct GNUNET_FS_BlockOptions *bo, - enum GNUNET_FS_PublishOptions options, - GNUNET_FS_PublishContinuation cont, void *cont_cls) -{ - struct PublishKskContext *pkc; - char *uris; - size_t size; - char *kbe; - char *sptr; - - GNUNET_assert (NULL != uri); - pkc = GNUNET_malloc (sizeof (struct PublishKskContext)); - pkc->h = h; - pkc->bo = *bo; - pkc->cont = cont; - pkc->cont_cls = cont_cls; - if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) - { - pkc->dsh = GNUNET_DATASTORE_connect (h->cfg); - if (pkc->dsh == NULL) - { - cont (cont_cls, NULL, _("Could not connect to datastore.")); - GNUNET_free (pkc); - return; - } - } - if (meta == NULL) - pkc->mdsize = 0; - else - pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); - GNUNET_assert (pkc->mdsize >= 0); - uris = GNUNET_FS_uri_to_string (uri); - pkc->slen = strlen (uris) + 1; - size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen; - if (size > MAX_KBLOCK_SIZE) - { - size = MAX_KBLOCK_SIZE; - pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen; - } - pkc->kb = GNUNET_malloc (size); - kbe = (char *) &pkc->kb[1]; - memcpy (kbe, uris, pkc->slen); - GNUNET_free (uris); - sptr = &kbe[pkc->slen]; - if (meta != NULL) - pkc->mdsize = - GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, pkc->mdsize, - GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); - if (pkc->mdsize == -1) - { - GNUNET_break (0); - GNUNET_free (pkc->kb); - if (pkc->dsh != NULL) - { - GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); - pkc->dsh = NULL; - } - cont (cont_cls, NULL, _("Internal error.")); - GNUNET_free (pkc); - return; - } - size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize; - - pkc->cpy = GNUNET_malloc (size); - pkc->cpy->purpose.size = - htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + - pkc->mdsize + pkc->slen); - pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK); - pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); - GNUNET_SCHEDULER_add_continuation (&publish_ksk_cont, pkc, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); -} - /* end of fs_publish.c */ diff --git a/src/fs/fs_publish_ksk.c b/src/fs/fs_publish_ksk.c new file mode 100644 index 000000000..5119de4c5 --- /dev/null +++ b/src/fs/fs_publish_ksk.c @@ -0,0 +1,342 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file fs/fs_publish_ksk.c + * @brief publish a URI under a keyword in GNUnet + * @see https://gnunet.org/encoding + * @author Krista Bennett + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_signatures.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "fs_api.h" +#include "fs_tree.h" + + +/** + * Maximum legal size for a kblock. + */ +#define MAX_KBLOCK_SIZE (60 * 1024) + + +/** + * Context for the KSK publication. + */ +struct GNUNET_FS_PublishKskContext +{ + + /** + * Keywords to use. + */ + struct GNUNET_FS_Uri *ksk_uri; + + /** + * Global FS context. + */ + struct GNUNET_FS_Handle *h; + + /** + * The master block that we are sending + * (in plaintext), has "mdsize+slen" more + * bytes than the struct would suggest. + */ + struct KBlock *kb; + + /** + * Buffer of the same size as "kb" for + * the encrypted version. + */ + struct KBlock *cpy; + + /** + * Handle to the datastore, NULL if we are just + * simulating. + */ + struct GNUNET_DATASTORE_Handle *dsh; + + /** + * Handle to datastore PUT request. + */ + struct GNUNET_DATASTORE_QueueEntry *qre; + + /** + * Current task. + */ + GNUNET_SCHEDULER_TaskIdentifier ksk_task; + + /** + * Function to call once we're done. + */ + GNUNET_FS_PublishContinuation cont; + + /** + * Closure for cont. + */ + void *cont_cls; + + /** + * When should the KBlocks expire? + */ + struct GNUNET_FS_BlockOptions bo; + + /** + * Size of the serialized metadata. + */ + ssize_t mdsize; + + /** + * Size of the (CHK) URI as a string. + */ + size_t slen; + + /** + * Keyword that we are currently processing. + */ + unsigned int i; + +}; + + +/** + * Continuation of "GNUNET_FS_publish_ksk" that performs + * the actual publishing operation (iterating over all + * of the keywords). + * + * @param cls closure of type "struct PublishKskContext*" + * @param tc unused + */ +static void +publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Function called by the datastore API with + * the result from the PUT request. + * + * @param cls closure of type "struct GNUNET_FS_PublishKskContext*" + * @param success GNUNET_OK on success + * @param min_expiration minimum expiration time required for content to be stored + * @param msg error message (or NULL) + */ +static void +kb_put_cont (void *cls, int success, + struct GNUNET_TIME_Absolute min_expiration, + const char *msg) +{ + struct GNUNET_FS_PublishKskContext *pkc = cls; + + pkc->qre = NULL; + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "KBlock PUT operation failed: %s\n", msg); + pkc->cont (pkc->cont_cls, NULL, msg); + GNUNET_FS_publish_ksk_cancel (pkc); + return; + } + pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); +} + + +/** + * Continuation of "GNUNET_FS_publish_ksk" that performs the actual + * publishing operation (iterating over all of the keywords). + * + * @param cls closure of type "struct GNUNET_FS_PublishKskContext*" + * @param tc unused + */ +static void +publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_FS_PublishKskContext *pkc = cls; + const char *keyword; + GNUNET_HashCode key; + GNUNET_HashCode query; + struct GNUNET_CRYPTO_AesSessionKey skey; + struct GNUNET_CRYPTO_AesInitializationVector iv; + struct GNUNET_CRYPTO_RsaPrivateKey *pk; + + pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK; + if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK PUT operation complete\n"); + pkc->cont (pkc->cont_cls, pkc->ksk_uri, NULL); + GNUNET_FS_publish_ksk_cancel (pkc); + return; + } + keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n", + keyword); + /* first character of keyword indicates if it is + * mandatory or not -- ignore for hashing */ + GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); + GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); + GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1], pkc->slen + pkc->mdsize, &skey, &iv, + &pkc->cpy[1]); + pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); + GNUNET_assert (NULL != pk); + GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace); + GNUNET_CRYPTO_hash (&pkc->cpy->keyspace, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &query); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (pk, &pkc->cpy->purpose, + &pkc->cpy->signature)); + GNUNET_CRYPTO_rsa_key_free (pk); + pkc->qre = + GNUNET_DATASTORE_put (pkc->dsh, 0, &query, + pkc->mdsize + sizeof (struct KBlock) + pkc->slen, + pkc->cpy, GNUNET_BLOCK_TYPE_FS_KBLOCK, + pkc->bo.content_priority, pkc->bo.anonymity_level, + pkc->bo.replication_level, pkc->bo.expiration_time, + -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, + &kb_put_cont, pkc); +} + + +/** + * Publish a CHK under various keywords on GNUnet. + * + * @param h handle to the file sharing subsystem + * @param ksk_uri keywords to use + * @param meta metadata to use + * @param uri URI to refer to in the KBlock + * @param bo per-block options + * @param options publication options + * @param cont continuation + * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) + */ +struct GNUNET_FS_PublishKskContext * +GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, + const struct GNUNET_FS_Uri *ksk_uri, + const struct GNUNET_CONTAINER_MetaData *meta, + const struct GNUNET_FS_Uri *uri, + const struct GNUNET_FS_BlockOptions *bo, + enum GNUNET_FS_PublishOptions options, + GNUNET_FS_PublishContinuation cont, void *cont_cls) +{ + struct GNUNET_FS_PublishKskContext *pkc; + char *uris; + size_t size; + char *kbe; + char *sptr; + + GNUNET_assert (NULL != uri); + pkc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishKskContext)); + pkc->h = h; + pkc->bo = *bo; + pkc->cont = cont; + pkc->cont_cls = cont_cls; + if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) + { + pkc->dsh = GNUNET_DATASTORE_connect (h->cfg); + if (NULL == pkc->dsh) + { + cont (cont_cls, NULL, _("Could not connect to datastore.")); + GNUNET_free (pkc); + return NULL; + } + } + if (meta == NULL) + pkc->mdsize = 0; + else + pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); + GNUNET_assert (pkc->mdsize >= 0); + uris = GNUNET_FS_uri_to_string (uri); + pkc->slen = strlen (uris) + 1; + size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen; + if (size > MAX_KBLOCK_SIZE) + { + size = MAX_KBLOCK_SIZE; + pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen; + } + pkc->kb = GNUNET_malloc (size); + kbe = (char *) &pkc->kb[1]; + memcpy (kbe, uris, pkc->slen); + GNUNET_free (uris); + sptr = &kbe[pkc->slen]; + if (meta != NULL) + pkc->mdsize = + GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, pkc->mdsize, + GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); + if (-1 == pkc->mdsize) + { + GNUNET_break (0); + GNUNET_free (pkc->kb); + if (pkc->dsh != NULL) + { + GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); + pkc->dsh = NULL; + } + GNUNET_free (pkc); + cont (cont_cls, NULL, _("Internal error.")); + return NULL; + } + size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize; + + pkc->cpy = GNUNET_malloc (size); + pkc->cpy->purpose.size = + htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + pkc->mdsize + pkc->slen); + pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK); + pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); + pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); + return pkc; +} + + +/** + * Abort the KSK publishing operation. + * + * @param pkc context of the operation to abort. + */ +void +GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc) +{ + if (GNUNET_SCHEDULER_NO_TASK != pkc->ksk_task) + { + GNUNET_SCHEDULER_cancel (pkc->ksk_task); + pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != pkc->qre) + { + GNUNET_DATASTORE_cancel (pkc->qre); + pkc->qre = NULL; + } + if (NULL != pkc->dsh) + { + GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); + pkc->dsh = NULL; + } + GNUNET_free (pkc->cpy); + GNUNET_free (pkc->kb); + GNUNET_FS_uri_destroy (pkc->ksk_uri); + GNUNET_free (pkc); +} + + +/* end of fs_publish_ksk.c */ diff --git a/src/fs/fs_tree.c b/src/fs/fs_tree.c index fc04446c9..2ac38ffd3 100644 --- a/src/fs/fs_tree.c +++ b/src/fs/fs_tree.c @@ -360,8 +360,7 @@ GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te) if (pt_size != te->reader (te->cls, te->publish_offset, pt_size, iob, &te->emsg)) { - GNUNET_SCHEDULER_add_continuation (te->cont, te->cls, - GNUNET_SCHEDULER_REASON_TIMEOUT); + te->cont (te->cls, NULL); te->in_next = GNUNET_NO; return; } diff --git a/src/fs/gnunet-fs.c b/src/fs/gnunet-fs.c index 8cf08ec28..0b2892371 100644 --- a/src/fs/gnunet-fs.c +++ b/src/fs/gnunet-fs.c @@ -46,20 +46,6 @@ static int list_indexed_files; static int verbose; -/** - * Shutdown this process. - * - * @param cls unused - * @param tc unused - */ -static void -do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_FS_stop (fs); - fs = NULL; -} - - /** * Print indexed filenames to stdout. * @@ -71,6 +57,12 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static int print_indexed (void *cls, const char *filename, const GNUNET_HashCode * file_id) { + if (NULL == filename) + { + GNUNET_FS_stop (fs); + fs = NULL; + return GNUNET_OK; + } if (verbose) FPRINTF (stdout, "%s: %s\n", GNUNET_h2s (file_id), filename); else @@ -100,7 +92,13 @@ run (void *cls, char *const *args, const char *cfgfile, ret = 1; return; } - GNUNET_FS_get_indexed_files (fs, &print_indexed, NULL, &do_shutdown, NULL); + if (NULL == GNUNET_FS_get_indexed_files (fs, &print_indexed, NULL)) + { + ret = 2; + GNUNET_FS_stop (fs); + fs = NULL; + return; + } } } diff --git a/src/fs/gnunet-publish.c b/src/fs/gnunet-publish.c index 370f1062c..8f8d9147c 100644 --- a/src/fs/gnunet-publish.c +++ b/src/fs/gnunet-publish.c @@ -356,7 +356,7 @@ uri_ksk_continuation (void *cls, const struct GNUNET_FS_Uri *ksk_uri, { GNUNET_FS_publish_sks (ctx, ns, this_id, next_id, meta, uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, - uri_sks_continuation, NULL); + &uri_sks_continuation, NULL); GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_NO)); return; } diff --git a/src/include/gnunet_fs_service.h b/src/include/gnunet_fs_service.h index 0c739709d..3af4e50f9 100644 --- a/src/include/gnunet_fs_service.h +++ b/src/include/gnunet_fs_service.h @@ -2022,6 +2022,12 @@ typedef void (*GNUNET_FS_PublishContinuation) (void *cls, const char *emsg); +/** + * Handle to cancel publish KSK operation. + */ +struct GNUNET_FS_PublishKskContext; + + /** * Publish a KBlock on GNUnet. * @@ -2033,8 +2039,9 @@ typedef void (*GNUNET_FS_PublishContinuation) (void *cls, * @param options publication options * @param cont continuation * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) */ -void +struct GNUNET_FS_PublishKskContext * GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *ksk_uri, const struct GNUNET_CONTAINER_MetaData *meta, @@ -2044,6 +2051,21 @@ GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, GNUNET_FS_PublishContinuation cont, void *cont_cls); +/** + * Abort the KSK publishing operation. + * + * @param pkc context of the operation to abort. + */ +void +GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc); + + +/** + * Handle to cancel publish SKS operation. + */ +struct GNUNET_FS_PublishSksContext; + + /** * Publish an SBlock on GNUnet. * @@ -2057,8 +2079,9 @@ GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, * @param options publication options * @param cont continuation * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) */ -void +struct GNUNET_FS_PublishSksContext * GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, struct GNUNET_FS_Namespace *namespace, const char *identifier, const char *update, @@ -2069,11 +2092,20 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, GNUNET_FS_PublishContinuation cont, void *cont_cls); +/** + * Abort the SKS publishing operation. + * + * @param psc context of the operation to abort. + */ +void +GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc); + + /** * Type of a function called by "GNUNET_FS_get_indexed_files". * * @param cls closure - * @param filename the name of the file + * @param filename the name of the file, NULL for end of list * @param file_id hash of the contents of the indexed file * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort */ @@ -2081,22 +2113,33 @@ typedef int (*GNUNET_FS_IndexedFileProcessor) (void *cls, const char *filename, const GNUNET_HashCode * file_id); +/** + * Handle to cancel 'GNUNET_FS_get_indexed_files'. + */ +struct GNUNET_FS_GetIndexedContext; + + /** * Iterate over all indexed files. * * @param h handle to the file sharing subsystem * @param iterator function to call on each indexed file * @param iterator_cls closure for iterator - * @param cont continuation to call when done; - * reason should be "TIMEOUT" (on - * error) or "PREREQ_DONE" (on success) - * @param cont_cls closure for cont + * @return NULL on error ('iter' is not called) */ -void +struct GNUNET_FS_GetIndexedContext * GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, GNUNET_FS_IndexedFileProcessor iterator, - void *iterator_cls, GNUNET_SCHEDULER_Task cont, - void *cont_cls); + void *iterator_cls); + + +/** + * Cancel iteration over all indexed files. + * + * @param gic operation to cancel + */ +void +GNUNET_FS_get_indexed_files_cancel (struct GNUNET_FS_GetIndexedContext *gic); /** @@ -2121,6 +2164,12 @@ void GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc); +/** + * Context for advertising a namespace. + */ +struct GNUNET_FS_AdvertisementContext; + + /** * Publish an advertismement for a namespace. * @@ -2132,8 +2181,9 @@ GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc); * @param rootEntry name of the root of the namespace * @param cont continuation * @param cont_cls closure for cont + * @return NULL on error ('cont' will still be called) */ -void +struct GNUNET_FS_AdvertisementContext * GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, struct GNUNET_FS_Uri *ksk_uri, struct GNUNET_FS_Namespace *namespace, @@ -2144,6 +2194,15 @@ GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, void *cont_cls); +/** + * Abort the namespace advertisement operation. + * + * @param pkc context of the operation to abort. + */ +void +GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac); + + /** * Create a namespace with the given name; if one already * exists, return a handle to the existing namespace.