/** * Create an entry for a file in a publish-structure. * * @param h handle to the file sharing subsystem * @param client_info initial value for the client-info value for this entry * @param length length of the file * @param reader function that can be used to obtain the data for the file * @param reader_cls closure for "reader" * @param keywords under which keywords should this file be available * directly; can be NULL * @param meta metadata for the file * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param bo block options * @return publish structure entry for the file */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_from_reader (struct GNUNET_FS_Handle *h, void *client_info, uint64_t length, GNUNET_FS_DataReader reader, void *reader_cls, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, int do_index, const struct GNUNET_FS_BlockOptions *bo) { struct GNUNET_FS_FileInformation *ret; if ((GNUNET_YES == do_index) && (reader != &GNUNET_FS_data_reader_file_)) { GNUNET_break (0); return NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); ret->h = h; ret->client_info = client_info; ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); if (ret->meta == NULL) ret->meta = GNUNET_CONTAINER_meta_data_create (); ret->keywords = (keywords == NULL) ? NULL : GNUNET_FS_uri_dup (keywords); ret->data.file.reader = reader; ret->data.file.reader_cls = reader_cls; ret->data.file.do_index = do_index; ret->data.file.file_size = length; ret->bo = *bo; return ret; }
/** * Create an entry for an empty directory in a publish-structure. * This function should be used by applications for which the * use of "GNUNET_FS_file_information_create_from_directory" * is not appropriate. * * @param h handle to the file sharing subsystem * @param client_info initial value for the client-info value for this entry * @param meta metadata for the directory * @param keywords under which keywords should this directory be available * directly; can be NULL * @param bo block options * @param filename name of the directory; can be NULL * @return publish structure entry for the directory , NULL on error */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h, void *client_info, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_BlockOptions *bo, const char *filename) { struct GNUNET_FS_FileInformation *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); ret->h = h; ret->client_info = client_info; ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); ret->keywords = GNUNET_FS_uri_dup (keywords); ret->bo = *bo; ret->is_directory = GNUNET_YES; if (filename != NULL) ret->filename = GNUNET_strdup (filename); return ret; }
static void sks_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *ksk_uri; char *msg; struct GNUNET_FS_BlockOptions bo; if (NULL == uri) { fprintf (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } meta = GNUNET_CONTAINER_meta_data_create (); msg = NULL; ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg); GNUNET_assert (NULL == msg); ksk_expect_uri = GNUNET_FS_uri_dup (uri); bo.content_priority = 1; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); GNUNET_FS_publish_ksk (fs, ksk_uri, meta, uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &publish_cont, NULL); GNUNET_FS_uri_destroy (ksk_uri); GNUNET_CONTAINER_meta_data_destroy (meta); }
static void adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_CRYPTO_EcdsaPrivateKey *ns; struct GNUNET_FS_BlockOptions bo; if (NULL != emsg) { FPRINTF (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } ns = GNUNET_CRYPTO_ecdsa_key_create (); meta = GNUNET_CONTAINER_meta_data_create (); sks_expect_uri = GNUNET_FS_uri_dup (uri); bo.content_priority = 1; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); GNUNET_CRYPTO_ecdsa_key_get_public (ns, &nsid); GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont, NULL); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_free (ns); }
static void do_wait (void *cls, const struct GNUNET_FS_Uri *uri, const char *fn) { struct DownloadContext *dc; if (NULL == uri) { GNUNET_SCHEDULER_shutdown (); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting to allow content to migrate\n"); dc = GNUNET_new (struct DownloadContext); dc->uri = GNUNET_FS_uri_dup (uri); if (NULL != fn) dc->fn = GNUNET_strdup (fn); (void) GNUNET_SCHEDULER_add_delayed (MIGRATION_DELAY, &stop_source_peer, dc); }
static void do_publish2 (void *cls, const struct GNUNET_FS_Uri *u1, const char *fn) { int do_index; int anonymity; if (NULL == u1) { cleanup (); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } if (NULL != fn) fn1 = GNUNET_strdup (fn); uri1 = GNUNET_FS_uri_dup (u1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", (unsigned long long) FILESIZE); if (NULL != strstr (progname, "index")) do_index = GNUNET_YES; else do_index = GNUNET_NO; if (NULL != strstr (progname, "dht")) anonymity = 0; else anonymity = 1; GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, do_index, FILESIZE, SEED2, VERBOSE, &do_downloads, NULL); }
/** * Start download probes for the given search result. * * @param h file-sharing handle to use for the operation * @param uri URI to probe * @param meta meta data associated with the URI * @param client_info client info pointer to use for associated events * @param anonymity anonymity level to use for the probes * @return the search result handle to access the probe activity */ struct GNUNET_FS_SearchResult * GNUNET_FS_probe (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, void *client_info, uint32_t anonymity) { struct GNUNET_FS_SearchResult *sr; GNUNET_assert (NULL != h); sr = GNUNET_new (struct GNUNET_FS_SearchResult); sr->h = h; sr->uri = GNUNET_FS_uri_dup (uri); sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); sr->client_info = client_info; sr->anonymity = anonymity; GNUNET_FS_search_start_probe_ (sr); return sr; }
/** * Function called by the directory scanner as we extract keywords * that we will need to remove UBlocks. * * @param cls the 'struct GNUNET_FS_UnindexContext *' * @param filename which file we are making progress on * @param is_directory #GNUNET_YES if this is a directory, * #GNUNET_NO if this is a file * #GNUNET_SYSERR if it is neither (or unknown) * @param reason kind of progress we are making */ static void unindex_directory_scan_cb (void *cls, const char *filename, int is_directory, enum GNUNET_FS_DirScannerProgressUpdateReason reason) { struct GNUNET_FS_UnindexContext *uc = cls; static struct GNUNET_FS_ShareTreeItem * directory_scan_result; switch (reason) { case GNUNET_FS_DIRSCANNER_FINISHED: directory_scan_result = GNUNET_FS_directory_scan_get_result (uc->dscan); uc->dscan = NULL; if (NULL != directory_scan_result->ksk_uri) { uc->ksk_uri = GNUNET_FS_uri_dup (directory_scan_result->ksk_uri); uc->state = UNINDEX_STATE_DS_REMOVE_KBLOCKS; GNUNET_FS_unindex_sync_ (uc); GNUNET_FS_unindex_do_remove_kblocks_ (uc); } else { uc->emsg = GNUNET_strdup (_("Failed to get KSKs from directory scan.")); GNUNET_FS_unindex_sync_ (uc); unindex_finish (uc); } GNUNET_FS_share_tree_free (directory_scan_result); break; case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Internal error scanning `%s'.\n"), uc->filename); GNUNET_FS_directory_scan_abort (uc->dscan); uc->dscan = NULL; uc->emsg = GNUNET_strdup (_("Failed to get KSKs from directory scan.")); GNUNET_FS_unindex_sync_ (uc); unindex_finish (uc); break; default: break; } }
/** * We have received a KSK result. Check how it fits in with the * overall query and notify the client accordingly. * * @param sc context for the overall query * @param ent entry for the specific keyword * @param uri the URI that was found * @param meta metadata associated with the URI * under the @a ent keyword */ static void process_ksk_result (struct GNUNET_FS_SearchContext *sc, struct SearchRequestEntry *ent, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta) { struct GNUNET_HashCode key; struct GNUNET_FS_SearchResult *sr; struct GetResultContext grc; int is_new; unsigned int koff; /* check if new */ GNUNET_assert (NULL != sc); GNUNET_FS_uri_to_key (uri, &key); if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_get_multiple (ent->results, &key, &test_result_present, (void *) uri)) return; /* duplicate result */ /* try to find search result in master map */ grc.sr = NULL; grc.uri = uri; GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key, &get_result_present, &grc); sr = grc.sr; is_new = (NULL == sr) || (sr->mandatory_missing > 0); if (NULL == sr) { sr = GNUNET_new (struct GNUNET_FS_SearchResult); sr->h = sc->h; sr->sc = sc; sr->anonymity = sc->anonymity; sr->uri = GNUNET_FS_uri_dup (uri); sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); sr->mandatory_missing = sc->mandatory_count; sr->key = key; sr->keyword_bitmap = GNUNET_malloc ((sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */ GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); }
static void do_downloads (void *cls, const struct GNUNET_FS_Uri *u2, const char *fn) { int anonymity; unsigned int i; if (NULL == u2) { cleanup (); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } if (NULL != fn) fn2 = GNUNET_strdup (fn); uri2 = GNUNET_FS_uri_dup (u2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", (unsigned long long) FILESIZE); start_time = GNUNET_TIME_absolute_get (); if (NULL != strstr (progname, "dht")) anonymity = 0; else anonymity = 1; /* (semi) leach-download(s); not true leaches since * these peers do participate in sharing, they just * don't have to offer anything *initially*. */ for (i = 0; i < NUM_DAEMONS - 2; i++) GNUNET_FS_TEST_download (daemons[i], TIMEOUT, anonymity, 0 == (i % 2) ? SEED1 : SEED2, 0 == (i % 2) ? uri1 : uri2, VERBOSE, &do_report, "leach"); /* mutual downloads of (primary) sharing peers */ GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, SEED1, uri1, VERBOSE, &do_report, "seeder 2"); GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, SEED2, uri2, VERBOSE, &do_report, "seeder 1"); }
/** * 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; }
/** * Process a share item tree, moving frequent keywords up and * copying frequent metadata up. * * @param tc trim context with hash maps to use * @param tree tree to trim */ static void share_tree_trim (struct TrimContext *tc, struct GNUNET_FS_ShareTreeItem *tree) { struct GNUNET_FS_ShareTreeItem *pos; unsigned int num_children; /* first, trim all children */ num_children = 0; for (pos = tree->children_head; NULL != pos; pos = pos->next) { share_tree_trim (tc, pos); num_children++; } /* consider adding filename to directory meta data */ if (tree->is_directory == GNUNET_YES) { const char *user = getenv ("USER"); if ( (user == NULL) || (0 != strncasecmp (user, tree->short_filename, strlen(user)))) { /* only use filename if it doesn't match $USER */ if (NULL == tree->meta) tree->meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (tree->meta, "<libgnunetfs>", EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", tree->short_filename, strlen (tree->short_filename) + 1); } } if (1 >= num_children) return; /* nothing to trim */ /* now, count keywords and meta data in children */ for (pos = tree->children_head; NULL != pos; pos = pos->next) { if (NULL != pos->meta) GNUNET_CONTAINER_meta_data_iterate (pos->meta, &add_to_meta_counter, tc->metacounter); if (NULL != pos->ksk_uri) GNUNET_FS_uri_ksk_get_keywords (pos->ksk_uri, &add_to_keyword_counter, tc->keywordcounter); } /* calculate threshold for moving keywords / meta data */ tc->move_threshold = 1 + (num_children / 2); /* remove high-frequency keywords from children */ for (pos = tree->children_head; NULL != pos; pos = pos->next) { tc->pos = pos; if (NULL != pos->ksk_uri) { struct GNUNET_FS_Uri *ksk_uri_copy = GNUNET_FS_uri_dup (pos->ksk_uri); GNUNET_FS_uri_ksk_get_keywords (ksk_uri_copy, &remove_high_frequency_keywords, tc); GNUNET_FS_uri_destroy (ksk_uri_copy); } } /* add high-frequency meta data and keywords to parent */ tc->pos = tree; GNUNET_CONTAINER_multihashmap_iterate (tc->keywordcounter, &migrate_and_drop_keywords, tc); GNUNET_CONTAINER_multihashmap_iterate (tc->metacounter, &migrate_and_drop_metadata, tc); }