/** * Extract metadata from files. * * @param item entry we are processing * @return GNUNET_OK on success, GNUNET_SYSERR on fatal errors */ static int extract_files (struct ScanTreeNode *item) { struct GNUNET_CONTAINER_MetaData *meta; ssize_t size; size_t slen; if (GNUNET_YES == item->is_directory) { /* for directories, we simply only descent, no extraction, no progress reporting */ struct ScanTreeNode *pos; for (pos = item->children_head; NULL != pos; pos = pos->next) if (GNUNET_OK != extract_files (pos)) return GNUNET_SYSERR; return GNUNET_OK; } /* this is the expensive operation, *afterwards* we'll check for aborts */ meta = GNUNET_CONTAINER_meta_data_create (); if (NULL != plugins) EXTRACTOR_extract (plugins, item->filename, NULL, 0, &add_to_md, meta); slen = strlen (item->filename) + 1; size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); if (-1 == size) { /* no meta data */ GNUNET_CONTAINER_meta_data_destroy (meta); if (GNUNET_OK != write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, item->filename, slen)) return GNUNET_SYSERR; return GNUNET_OK; } { char buf[size + slen]; char *dst = &buf[slen]; memcpy (buf, item->filename, slen); size = GNUNET_CONTAINER_meta_data_serialize (meta, &dst, size, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (size < 0) { GNUNET_break (0); size = 0; } GNUNET_CONTAINER_meta_data_destroy (meta); if (GNUNET_OK != write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, buf, slen + size)) return GNUNET_SYSERR; } return GNUNET_OK; }
/** * Transmit a join request to the chat service. * * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_join_request (void *cls, size_t size, void *buf) { struct GNUNET_CHAT_Room *chat_room = cls; struct JoinRequestMessage *join_msg; char *room; char *meta; size_t room_len; ssize_t meta_len; size_t size_of_join; if (NULL == buf) { #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit join request, retrying...\n"); #endif rejoin_room (chat_room); return 0; } #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting join request to the service\n"); #endif room_len = strlen (chat_room->room_name); meta_len = GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info); size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len; GNUNET_assert (size >= size_of_join); join_msg = buf; join_msg->header.size = htons (size); join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST); join_msg->msg_options = htonl (chat_room->msg_options); join_msg->room_name_len = htons (room_len); join_msg->reserved = htons (0); join_msg->reserved2 = htonl (0); GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key, &join_msg->public_key); room = (char *) &join_msg[1]; memcpy (room, chat_room->room_name, room_len); meta = &room[room_len]; if (GNUNET_SYSERR == GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info, &meta, meta_len, GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n")); return 0; } GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, GNUNET_TIME_UNIT_FOREVER_REL); return size_of_join; }
/** * Ask to send a join request. */ static int rejoin_room (struct GNUNET_CHAT_Room *chat_room) { size_t size_of_join; size_of_join = sizeof (struct JoinRequestMessage) + GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info) + strlen (chat_room->room_name); if (NULL == GNUNET_CLIENT_notify_transmit_ready (chat_room->client, size_of_join, GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_YES, &transmit_join_request, chat_room)) return GNUNET_SYSERR; return GNUNET_OK; }
/** * Publish a UBlock. * * @param h handle to the file sharing subsystem * @param dsh datastore handle to use for storage operation * @param label identifier to use * @param ulabel update label to use, may be an empty string for none * @param ns namespace to publish in * @param meta metadata to use * @param uri URI to refer to in the UBlock * @param bo per-block options * @param options publication options * @param cont continuation * @param cont_cls closure for @a cont * @return NULL on error (@a cont will still be called) */ struct GNUNET_FS_PublishUblockContext * GNUNET_FS_publish_ublock_ (struct GNUNET_FS_Handle *h, struct GNUNET_DATASTORE_Handle *dsh, const char *label, const char *ulabel, const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns, 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_UBlockContinuation cont, void *cont_cls) { struct GNUNET_FS_PublishUblockContext *uc; struct GNUNET_HashCode query; struct GNUNET_CRYPTO_SymmetricInitializationVector iv; struct GNUNET_CRYPTO_SymmetricSessionKey skey; struct GNUNET_CRYPTO_EcdsaPrivateKey *nsd; struct GNUNET_CRYPTO_EcdsaPublicKey pub; char *uris; size_t size; char *kbe; char *sptr; ssize_t mdsize; size_t slen; size_t ulen; struct UBlock *ub_plain; struct UBlock *ub_enc; /* compute ublock to publish */ if (NULL == meta) mdsize = 0; else mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); GNUNET_assert (mdsize >= 0); uris = GNUNET_FS_uri_to_string (uri); slen = strlen (uris) + 1; if (NULL == ulabel) ulen = 1; else ulen = strlen (ulabel) + 1; size = mdsize + sizeof (struct UBlock) + slen + ulen; if (size > MAX_UBLOCK_SIZE) { size = MAX_UBLOCK_SIZE; mdsize = size - sizeof (struct UBlock) - (slen + ulen); } ub_plain = GNUNET_malloc (size); kbe = (char *) &ub_plain[1]; if (NULL != ulabel) memcpy (kbe, ulabel, ulen); kbe += ulen; memcpy (kbe, uris, slen); kbe += slen; GNUNET_free (uris); sptr = kbe; if (NULL != meta) mdsize = GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, mdsize, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (-1 == mdsize) { GNUNET_break (0); GNUNET_free (ub_plain); cont (cont_cls, _("Internal error.")); return NULL; } size = sizeof (struct UBlock) + slen + mdsize + ulen; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under identifier `%s'\n", label); /* get public key of the namespace */ GNUNET_CRYPTO_ecdsa_key_get_public (ns, &pub); derive_ublock_encryption_key (&skey, &iv, label, &pub); /* encrypt ublock */ ub_enc = GNUNET_malloc (size); GNUNET_CRYPTO_symmetric_encrypt (&ub_plain[1], ulen + slen + mdsize, &skey, &iv, &ub_enc[1]); GNUNET_free (ub_plain); ub_enc->purpose.size = htonl (ulen + slen + mdsize + sizeof (struct UBlock) - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); ub_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK); /* derive signing-key from 'label' and public key of the namespace */ nsd = GNUNET_CRYPTO_ecdsa_private_key_derive (ns, label, "fs-ublock"); GNUNET_CRYPTO_ecdsa_key_get_public (nsd, &ub_enc->verification_key); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (nsd, &ub_enc->purpose, &ub_enc->signature)); GNUNET_CRYPTO_hash (&ub_enc->verification_key, sizeof (ub_enc->verification_key), &query); GNUNET_free (nsd); uc = GNUNET_new (struct GNUNET_FS_PublishUblockContext); uc->cont = cont; uc->cont_cls = cont_cls; uc->qre = GNUNET_DATASTORE_put (dsh, 0, &query, ulen + slen + mdsize + sizeof (struct UBlock), ub_enc, GNUNET_BLOCK_TYPE_FS_UBLOCK, bo->content_priority, bo->anonymity_level, bo->replication_level, bo->expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &ublock_put_cont, uc); return uc; }
/** * 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; }
/** * Finish building the directory. Frees the * builder context and returns the directory * in-memory. * * @param bld directory to finish * @param rsize set to the number of bytes needed * @param rdata set to the encoded directory * @return GNUNET_OK on success */ int GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, size_t * rsize, void **rdata) { char *data; char *sptr; size_t *sizes; unsigned int *perm; unsigned int i; unsigned int j; struct BuilderEntry *pos; struct BuilderEntry **bes; size_t size; size_t psize; size_t off; ssize_t ret; uint32_t big; size = strlen (GNUNET_DIRECTORY_MAGIC) + sizeof (uint32_t); size += GNUNET_CONTAINER_meta_data_get_serialized_size (bld->meta); sizes = NULL; perm = NULL; bes = NULL; if (0 < bld->count) { sizes = GNUNET_malloc (bld->count * sizeof (size_t)); perm = GNUNET_malloc (bld->count * sizeof (unsigned int)); bes = GNUNET_malloc (bld->count * sizeof (struct BuilderEntry *)); pos = bld->head; for (i = 0; i < bld->count; i++) { perm[i] = i; bes[i] = pos; sizes[i] = pos->len; pos = pos->next; } block_align (size, bld->count, sizes, perm); /* compute final size with alignment */ for (i = 0; i < bld->count; i++) { psize = size; size += sizes[perm[i]]; size = do_align (psize, size); } } *rsize = size; data = GNUNET_malloc_large (size); if (data == NULL) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc"); *rsize = 0; *rdata = NULL; GNUNET_free_non_null (sizes); GNUNET_free_non_null (perm); GNUNET_free_non_null (bes); return GNUNET_SYSERR; } *rdata = data; memcpy (data, GNUNET_DIRECTORY_MAGIC, strlen (GNUNET_DIRECTORY_MAGIC)); off = strlen (GNUNET_DIRECTORY_MAGIC); sptr = &data[off + sizeof (uint32_t)]; ret = GNUNET_CONTAINER_meta_data_serialize (bld->meta, &sptr, size - off - sizeof (uint32_t), GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); GNUNET_assert (ret != -1); big = htonl (ret); memcpy (&data[off], &big, sizeof (uint32_t)); off += sizeof (uint32_t) + ret; for (j = 0; j < bld->count; j++) { i = perm[j]; psize = off; off += sizes[i]; off = do_align (psize, off); memcpy (&data[off - sizes[i]], &(bes[i])[1], sizes[i]); GNUNET_free (bes[i]); } GNUNET_free_non_null (sizes); GNUNET_free_non_null (perm); GNUNET_free_non_null (bes); GNUNET_assert (off == size); GNUNET_CONTAINER_meta_data_destroy (bld->meta); GNUNET_free (bld); return GNUNET_OK; }
/** * Add an entry to a directory. * * @param bld directory to extend * @param uri uri of the entry (must not be a KSK) * @param md metadata of the entry * @param data raw data of the entry, can be NULL, otherwise * data must point to exactly the number of bytes specified * by the uri which must be of type LOC or CHK */ void GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *md, const void *data) { struct GNUNET_FS_Uri *curi; struct BuilderEntry *e; uint64_t fsize; uint32_t big; ssize_t ret; size_t mds; size_t mdxs; char *uris; char *ser; char *sptr; size_t slen; struct GNUNET_CONTAINER_MetaData *meta; const struct GNUNET_CONTAINER_MetaData *meta_use; GNUNET_assert (!GNUNET_FS_uri_test_ksk (uri)); if (NULL != data) { GNUNET_assert (!GNUNET_FS_uri_test_sks (uri)); if (GNUNET_FS_uri_test_chk (uri)) { fsize = GNUNET_FS_uri_chk_get_file_size (uri); } else { curi = GNUNET_FS_uri_loc_get_uri (uri); GNUNET_assert (NULL != curi); fsize = GNUNET_FS_uri_chk_get_file_size (curi); GNUNET_FS_uri_destroy (curi); } } else { fsize = 0; /* not given */ } if (fsize > MAX_INLINE_SIZE) fsize = 0; /* too large */ uris = GNUNET_FS_uri_to_string (uri); slen = strlen (uris) + 1; mds = GNUNET_CONTAINER_meta_data_get_serialized_size (md); meta_use = md; meta = NULL; if (fsize > 0) { meta = GNUNET_CONTAINER_meta_data_duplicate (md); GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", EXTRACTOR_METATYPE_GNUNET_FULL_DATA, EXTRACTOR_METAFORMAT_BINARY, NULL, data, fsize); mdxs = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); if ((slen + sizeof (uint32_t) + mdxs - 1) / DBLOCK_SIZE == (slen + sizeof (uint32_t) + mds - 1) / DBLOCK_SIZE) { /* adding full data would not cause us to cross * additional blocks, so add it! */ meta_use = meta; mds = mdxs; } } if (mds > GNUNET_MAX_MALLOC_CHECKED / 2) mds = GNUNET_MAX_MALLOC_CHECKED / 2; e = GNUNET_malloc (sizeof (struct BuilderEntry) + slen + mds + sizeof (uint32_t)); ser = (char *) &e[1]; memcpy (ser, uris, slen); GNUNET_free (uris); sptr = &ser[slen + sizeof (uint32_t)]; ret = GNUNET_CONTAINER_meta_data_serialize (meta_use, &sptr, mds, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (NULL != meta) GNUNET_CONTAINER_meta_data_destroy (meta); if (ret == -1) mds = 0; else mds = ret; big = htonl (mds); memcpy (&ser[slen], &big, sizeof (uint32_t)); e->len = slen + sizeof (uint32_t) + mds; e->next = bld->head; bld->head = e; bld->count++; }