From: Christian Grothoff Date: Sat, 1 Oct 2016 12:53:07 +0000 (+0000) Subject: migrating fs to new service API X-Git-Tag: initial-import-from-subversion-38251~165 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=f7fac7f6736df4e350a8b5ed7d9f51782d7e039e;p=oweals%2Fgnunet.git migrating fs to new service API --- diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am index 736339aab..34f44f574 100644 --- a/src/fs/Makefile.am +++ b/src/fs/Makefile.am @@ -190,7 +190,6 @@ gnunet_service_fs_SOURCES = \ gnunet-service-fs.c gnunet-service-fs.h \ gnunet-service-fs_cp.c gnunet-service-fs_cp.h \ gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \ - gnunet-service-fs_lc.c gnunet-service-fs_lc.h \ gnunet-service-fs_pe.c gnunet-service-fs_pe.h \ gnunet-service-fs_pr.c gnunet-service-fs_pr.h \ gnunet-service-fs_push.c gnunet-service-fs_push.h \ diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c index 4131b1670..c83d73555 100644 --- a/src/fs/gnunet-service-fs.c +++ b/src/fs/gnunet-service-fs.c @@ -68,6 +68,161 @@ #define INSANE_STATISTICS GNUNET_NO + +/** + * Doubly-linked list of requests we are performing + * on behalf of the same client. + */ +struct ClientRequest +{ + + /** + * This is a doubly-linked list. + */ + struct ClientRequest *next; + + /** + * This is a doubly-linked list. + */ + struct ClientRequest *prev; + + /** + * Request this entry represents. + */ + struct GSF_PendingRequest *pr; + + /** + * Client list this request belongs to. + */ + struct GSF_LocalClient *lc; + + /** + * Task scheduled to destroy the request. + */ + struct GNUNET_SCHEDULER_Task * kill_task; + +}; + + +/** + * Replies to be transmitted to the client. The actual + * response message is allocated after this struct. + */ +struct ClientResponse +{ + /** + * This is a doubly-linked list. + */ + struct ClientResponse *next; + + /** + * This is a doubly-linked list. + */ + struct ClientResponse *prev; + + /** + * Client list entry this response belongs to. + */ + struct GSF_LocalClient *lc; + + /** + * Number of bytes in the response. + */ + size_t msize; +}; + + +/** + * Information we track while handling an index + * start request from a client. + */ +struct IndexStartContext +{ + + /** + * This is a doubly linked list. + */ + struct IndexStartContext *next; + + /** + * This is a doubly linked list. + */ + struct IndexStartContext *prev; + + /** + * Name of the indexed file. + */ + char *filename; + + /** + * Context for transmitting confirmation to client. + */ + struct GSF_LocalClient *lc; + + /** + * Context for hashing of the file. + */ + struct GNUNET_CRYPTO_FileHashContext *fhc; + + /** + * Hash of the contents of the file. + */ + struct GNUNET_HashCode file_id; + +}; + + +/** + * A local client. + */ +struct GSF_LocalClient +{ + + /** + * ID of the client. + */ + struct GNUNET_SERVICE_Client *client; + + /** + * Queue for sending replies. + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Head of list of requests performed on behalf + * of this client right now. + */ + struct ClientRequest *cr_head; + + /** + * Tail of list of requests performed on behalf + * of this client right now. + */ + struct ClientRequest *cr_tail; + + /** + * This is a doubly linked list. + */ + struct IndexStartContext *isc_head; + + /** + * This is a doubly linked list. + */ + struct IndexStartContext *isc_tail; + + /** + * Head of linked list of responses. + */ + struct ClientResponse *res_head; + + /** + * Tail of linked list of responses. + */ + struct ClientResponse *res_tail; + +}; + + /* ****************************** globals ****************************** */ /** @@ -152,6 +307,11 @@ struct GNUNET_CORE_Handle *GSF_core; */ int GSF_enable_randomized_delays; +/** + * Identity of this peer. + */ +struct GNUNET_PeerIdentity GSF_my_id; + /* ***************************** locals ******************************* */ /** @@ -174,10 +334,183 @@ static struct GNUNET_SCHEDULER_Task * cover_age_task; */ static struct GNUNET_LOAD_Value *datastore_get_load; + /** - * Identity of this peer. + * Creates a fresh local client handle. + * + * @param cls NULL + * @param client handle of the client + * @param mq message queue for @a client + * @return handle to local client entry */ -struct GNUNET_PeerIdentity GSF_my_id; +static void * +client_connect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + struct GNUNET_MQ_Handle *mq) +{ + struct GSF_LocalClient *pos; + + pos = GNUNET_new (struct GSF_LocalClient); + pos->client = client; + pos->mq = mq; + return pos; +} + + +/** + * Free the given client request. + * + * @param cls the client request to free + */ +static void +client_request_destroy (void *cls) +{ + struct ClientRequest *cr = cls; + struct GSF_LocalClient *lc = cr->lc; + + cr->kill_task = NULL; + GNUNET_CONTAINER_DLL_remove (lc->cr_head, + lc->cr_tail, + cr); + GSF_pending_request_cancel_ (cr->pr, + GNUNET_YES); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches active"), + -1, + GNUNET_NO); + GNUNET_free (cr); +} + + +/** + * Handle a reply to a pending request. Also called if a request + * expires (then with data == NULL). The handler may be called + * many times (depending on the request type), but will not be + * called during or after a call to #GSF_pending_request_cancel() + * and will also not be called anymore after a call signalling + * expiration. + * + * @param cls user-specified closure + * @param eval evaluation of the result + * @param pr handle to the original pending request + * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" + * @param expiration when does @a data expire? + * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown) + * @param type type of the block + * @param data response data, NULL on request expiration + * @param data_len number of bytes in @a data + */ +static void +client_response_handler (void *cls, + enum GNUNET_BLOCK_EvaluationResult eval, + struct GSF_PendingRequest *pr, + uint32_t reply_anonymity_level, + struct GNUNET_TIME_Absolute expiration, + struct GNUNET_TIME_Absolute last_transmission, + enum GNUNET_BLOCK_Type type, + const void *data, + size_t data_len) +{ + struct ClientRequest *cr = cls; + struct GSF_LocalClient *lc; + struct GNUNET_MQ_Envelope *env; + struct ClientPutMessage *pm; + const struct GSF_PendingRequestData *prd; + + if (NULL == data) + { + /* local-only request, with no result, clean up. */ + if (NULL == cr->kill_task) + cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, + cr); + return; + } + prd = GSF_pending_request_get_data_ (pr); + GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY); + if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY)) + { + GNUNET_break (0); + return; + } + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop + ("# replies received for local clients"), 1, + GNUNET_NO); + GNUNET_assert (pr == cr->pr); + lc = cr->lc; + env = GNUNET_MQ_msg_extra (pm, + data_len, + GNUNET_MESSAGE_TYPE_FS_PUT); + pm->type = htonl (type); + pm->expiration = GNUNET_TIME_absolute_hton (expiration); + pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission); + pm->num_transmissions = htonl (prd->num_transmissions); + pm->respect_offered = htonl (prd->respect_offered); + GNUNET_memcpy (&pm[1], + data, + data_len); + GNUNET_MQ_send (lc->mq, + env); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queued reply to query `%s' for local client\n", + GNUNET_h2s (&prd->query)); + if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Evaluation %d - keeping query alive\n", + (int) eval); + return; + } + if (NULL == cr->kill_task) + cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, + cr); +} + + +/** + * A client disconnected from us. Tear down the local client + * record. + * + * @param cls unused + * @param client handle of the client + * @param app_ctx the `struct GSF_LocalClient` + */ +static void +client_disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + void *app_ctx) +{ + struct GSF_LocalClient *lc = app_ctx; + struct IndexStartContext *isc; + struct ClientRequest *cr; + struct ClientResponse *res; + + while (NULL != (cr = lc->cr_head)) + { + if (NULL != cr->kill_task) + GNUNET_SCHEDULER_cancel (cr->kill_task); + client_request_destroy (cr); + } + while (NULL != (res = lc->res_head)) + { + GNUNET_CONTAINER_DLL_remove (lc->res_head, + lc->res_tail, + res); + GNUNET_free (res); + } + while (NULL != (isc = lc->isc_head)) + { + GNUNET_CONTAINER_DLL_remove (lc->isc_head, + lc->isc_tail, + isc); + GNUNET_CRYPTO_hash_file_cancel (isc->fhc); + GNUNET_free (isc); + } + GNUNET_free (lc); +} + + + /** @@ -289,7 +622,7 @@ check_p2p_put (void *cls, const struct PutMessage *put) { enum GNUNET_BLOCK_Type type; - + type = ntohl (put->type); if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type) { @@ -373,7 +706,7 @@ check_p2p_get (void *cls, unsigned int bm; unsigned int bits; size_t bfsize; - + msize = ntohs (gm->header.size); bm = ntohl (gm->hash_bitmap); bits = 0; @@ -394,8 +727,8 @@ check_p2p_get (void *cls, { GNUNET_break_op (0); return GNUNET_SYSERR; - } - return GNUNET_OK; + } + return GNUNET_OK; } @@ -405,7 +738,7 @@ check_p2p_get (void *cls, * result status). Also signal that we can now * receive more request information from the client. * - * @param cls the client doing the request (`struct GNUNET_SERVER_Client`) + * @param cls the client doing the request (`struct GSF_LocalClient`) * @param pr the pending request we were processing * @param result final datastore lookup result */ @@ -414,11 +747,10 @@ start_p2p_processing (void *cls, struct GSF_PendingRequest *pr, enum GNUNET_BLOCK_EvaluationResult result) { - struct GNUNET_SERVER_Client *client = cls; + struct GSF_LocalClient *lc = cls; struct GSF_PendingRequestData *prd; - GNUNET_SERVER_receive_done (client, - GNUNET_OK); + GNUNET_SERVICE_client_continue (lc->client); if (GNUNET_BLOCK_EVALUATION_OK_LAST == result) return; /* we're done, 'pr' was already destroyed... */ prd = GSF_pending_request_get_data_ (pr); @@ -448,7 +780,33 @@ start_p2p_processing (void *cls, break; } } - GSF_consider_forwarding (NULL, pr, result); + GSF_consider_forwarding (NULL, + pr, + result); +} + + +/** + * Check #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request + * from client). + * + * @param cls identification of the client + * @param sm the actual message + * @return #GNUNET_OK if @a sm is well-formed + */ +static int +check_client_start_search (void *cls, + const struct SearchMessage *sm) +{ + uint16_t msize; + + msize = ntohs (sm->header.size) - sizeof (struct SearchMessage); + if (0 != msize % sizeof (struct GNUNET_HashCode)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; } @@ -456,63 +814,128 @@ start_p2p_processing (void *cls, * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request * from client). * - * @param cls closure - * @param client identification of the client - * @param message the actual message + * Responsible for creating the request entry itself and setting + * up reply callback and cancellation on client disconnect. + * + * @param cls identification of the client + * @param sm the actual message */ static void -handle_start_search (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) +handle_client_start_search (void *cls, + const struct SearchMessage *sm) { - struct GSF_PendingRequest *pr; - int ret; - - pr = NULL; - ret = GSF_local_client_start_search_handler_ (client, - message, - &pr); - switch (ret) - { - case GNUNET_SYSERR: - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - break; - case GNUNET_NO: - GNUNET_SERVER_receive_done (client, - GNUNET_OK); - break; - case GNUNET_YES: - GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES; - GSF_local_lookup_ (pr, - &start_p2p_processing, - client); - break; - default: - GNUNET_assert (0); + static struct GNUNET_PeerIdentity all_zeros; + struct GSF_LocalClient *lc = cls; + struct ClientRequest *cr; + struct GSF_PendingRequestData *prd; + uint16_t msize; + unsigned int sc; + enum GNUNET_BLOCK_Type type; + enum GSF_PendingRequestOptions options; + + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches received"), + 1, + GNUNET_NO); + msize = ntohs (sm->header.size) - sizeof (struct SearchMessage); + sc = msize / sizeof (struct GNUNET_HashCode); + type = ntohl (sm->type); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received request for `%s' of type %u from local client\n", + GNUNET_h2s (&sm->query), + (unsigned int) type); + cr = NULL; + /* detect duplicate UBLOCK requests */ + if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) || + (type == GNUNET_BLOCK_TYPE_ANY)) + { + cr = lc->cr_head; + while (NULL != cr) + { + prd = GSF_pending_request_get_data_ (cr->pr); + /* only unify with queries that hae not yet started local processing + (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a + matching query and type */ + if ((GNUNET_YES != prd->has_started) && + (0 != memcmp (&prd->query, + &sm->query, + sizeof (struct GNUNET_HashCode))) && + (prd->type == type)) + break; + cr = cr->next; + } + } + if (NULL != cr) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have existing request, merging content-seen lists.\n"); + GSF_pending_request_update_ (cr->pr, + (const struct GNUNET_HashCode *) &sm[1], + sc); + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches updated (merged content seen list)"), + 1, + GNUNET_NO); + } + else + { + GNUNET_STATISTICS_update (GSF_stats, + gettext_noop ("# client searches active"), + 1, + GNUNET_NO); + cr = GNUNET_new (struct ClientRequest); + cr->lc = lc; + GNUNET_CONTAINER_DLL_insert (lc->cr_head, + lc->cr_tail, + cr); + options = GSF_PRO_LOCAL_REQUEST; + if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options))) + options |= GSF_PRO_LOCAL_ONLY; + cr->pr = GSF_pending_request_create_ (options, type, + &sm->query, + (0 != + memcmp (&sm->target, + &all_zeros, + sizeof (struct GNUNET_PeerIdentity))) + ? &sm->target : NULL, NULL, 0, + 0 /* bf */ , + ntohl (sm->anonymity_level), + 0 /* priority */ , + 0 /* ttl */ , + 0 /* sender PID */ , + 0 /* origin PID */ , + (const struct GNUNET_HashCode *) &sm[1], sc, + &client_response_handler, + cr); } + if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options))) + { + GNUNET_SERVICE_client_continue (lc->client); + return; + } + GSF_pending_request_get_data_ (cr->pr)->has_started = GNUNET_YES; + GSF_local_lookup_ (cr->pr, + &start_p2p_processing, + lc); } /** * Handle request to sign a LOC URI (from client). * - * @param cls closure (NULL) - * @param client identification of the client - * @param message the actual message + * @param cls identification of the client + * @param msg the actual message */ static void -handle_loc_sign (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) +handle_client_loc_sign (void *cls, + const struct RequestLocSignatureMessage *msg) { - const struct RequestLocSignatureMessage *msg; + struct GSF_LocalClient *lc = cls; struct GNUNET_FS_Uri base; struct GNUNET_FS_Uri *loc; - struct ResponseLocSignatureMessage resp; - struct GSF_LocalClient *lc; + struct GNUNET_MQ_Envelope *env; + struct ResponseLocSignatureMessage *resp; - msg = (const struct RequestLocSignatureMessage *) message; GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT == ntohl (msg->purpose)); base.type = GNUNET_FS_URI_CHK; @@ -521,17 +944,228 @@ handle_loc_sign (void *cls, loc = GNUNET_FS_uri_loc_create (&base, pk, GNUNET_TIME_absolute_ntoh (msg->expiration_time)); - resp.header.size = htons (sizeof (struct ResponseLocSignatureMessage)); - resp.header.type = htons (GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE); - resp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); - resp.expiration_time = GNUNET_TIME_absolute_hton (loc->data.loc.expirationTime); - resp.signature = loc->data.loc.contentSignature; - resp.peer = loc->data.loc.peer; + env = GNUNET_MQ_msg (resp, + GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE); + resp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); + resp->expiration_time = GNUNET_TIME_absolute_hton (loc->data.loc.expirationTime); + resp->signature = loc->data.loc.contentSignature; + resp->peer = loc->data.loc.peer; GNUNET_FS_uri_destroy (loc); - lc = GSF_local_client_lookup_ (client); - GSF_local_client_transmit_ (lc, - &resp.header); - GNUNET_SERVER_receive_done (client, GNUNET_OK); + GNUNET_MQ_send (lc->mq, + env); + GNUNET_SERVICE_client_continue (lc->client); +} + + +/** + * Check INDEX_START-message. + * + * @param cls identification of the client + * @param ism the actual message + * @return #GNUNET_OK if @a ism is well-formed + */ +static int +check_client_index_start (void *cls, + const struct IndexStartMessage *ism) +{ + uint16_t msize; + char *fn; + + msize = ntohs (ism->header.size); + if (((const char *) ism)[msize - 1] != '\0') + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (0 != ism->reserved) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]); + if (NULL == fn) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_free (fn); + return GNUNET_OK; +} + + +/** + * We've validated the hash of the file we're about to index. Signal + * success to the client and update our internal data structures. + * + * @param isc the data about the index info entry for the request + */ +static void +signal_index_ok (struct IndexStartContext *isc) +{ + struct GSF_LocalClient *lc = isc->lc; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MessageHeader *msg; + + GNUNET_FS_add_to_index (isc->filename, + &isc->file_id); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); + GNUNET_MQ_send (lc->mq, + env); + GNUNET_free (isc->filename); + GNUNET_free (isc); + GNUNET_SERVICE_client_continue (lc->client); +} + + +/** + * Function called once the hash computation over an + * indexed file has completed. + * + * @param cls closure, our publishing context + * @param res resulting hash, NULL on error + */ +static void +hash_for_index_val (void *cls, + const struct GNUNET_HashCode *res) +{ + struct IndexStartContext *isc = cls; + struct GSF_LocalClient *lc = isc->lc; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MessageHeader *msg; + + GNUNET_CONTAINER_DLL_remove (lc->isc_head, + lc->isc_tail, + isc); + isc->fhc = NULL; + if ( (NULL == res) || + (0 != memcmp (res, + &isc->file_id, + sizeof (struct GNUNET_HashCode)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Hash mismatch trying to index file `%s' which does not have hash `%s'\n"), + isc->filename, + GNUNET_h2s (&isc->file_id)); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED); + GNUNET_MQ_send (lc->mq, + env); + GNUNET_SERVICE_client_continue (lc->client); + GNUNET_free (isc); + return; + } + signal_index_ok (isc); +} + + +/** + * Handle INDEX_START-message. + * + * @param cls identification of the client + * @param message the actual message + */ +static void +handle_client_index_start (void *cls, + const struct IndexStartMessage *ism) +{ + struct GSF_LocalClient *lc = cls; + struct IndexStartContext *isc; + char *fn; + uint64_t dev; + uint64_t ino; + uint64_t mydev; + uint64_t myino; + + fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]); + GNUNET_assert (NULL != fn); + dev = GNUNET_ntohll (ism->device); + ino = GNUNET_ntohll (ism->inode); + isc = GNUNET_new (struct IndexStartContext); + isc->filename = fn; + isc->file_id = ism->file_id; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received START_INDEX message for file `%s'\n", + isc->filename); + isc->lc = lc; + mydev = 0; + myino = 0; + if ( ( (dev != 0) || + (ino != 0) ) && + (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, + &mydev, + &myino)) && + (dev == mydev) && + (ino == myino) ) + { + /* fast validation OK! */ + signal_index_ok (isc); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n", + (unsigned long long) ino, + (unsigned long long) myino, + (unsigned int) dev, + (unsigned int) mydev); + /* slow validation, need to hash full file (again) */ + GNUNET_CONTAINER_DLL_insert (lc->isc_head, + lc->isc_tail, + isc); + isc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, + isc->filename, + HASHING_BLOCKSIZE, + &hash_for_index_val, + isc); + if (NULL == isc->fhc) + hash_for_index_val (isc, + NULL); +} + + +/** + * Handle INDEX_LIST_GET-message. + * + * @param cls closure + * @param message the actual message + */ +static void +handle_client_index_list_get (void *cls, + const struct GNUNET_MessageHeader *message) +{ + struct GSF_LocalClient *lc = cls; + + GNUNET_FS_indexing_send_list (lc->mq); + GNUNET_SERVICE_client_continue (lc->client); +} + + +/** + * Handle UNINDEX-message. + * + * @param cls identification of the client + * @param message the actual message + */ +static void +handle_client_unindex (void *cls, + const struct UnindexMessage *um) +{ + struct GSF_LocalClient *lc = cls; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MessageHeader *msg; + int found; + + GNUNET_break (0 == um->reserved); + found = GNUNET_FS_indexing_do_unindex (&um->file_id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client requested unindexing of file `%s': %s\n", + GNUNET_h2s (&um->file_id), + found ? "found" : "not found"); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK); + GNUNET_MQ_send (lc->mq, + env); + GNUNET_SERVICE_client_continue (lc->client); } @@ -560,7 +1194,8 @@ shutdown_task (void *cls) GSF_pending_request_done_ (); GSF_plan_done (); GSF_connected_peer_done_ (); - GNUNET_DATASTORE_disconnect (GSF_dsh, GNUNET_NO); + GNUNET_DATASTORE_disconnect (GSF_dsh, + GNUNET_NO); GSF_dsh = NULL; GNUNET_DHT_disconnect (GSF_dht); GSF_dht = NULL; @@ -610,12 +1245,10 @@ peer_init_handler (void *cls, /** * Process fs requests. * - * @param server the initialized server * @param c configuration to use */ static int -main_init (struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *c) +main_init (const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = { GNUNET_MQ_handler_end () @@ -635,22 +1268,6 @@ main_init (struct GNUNET_SERVER_Handle *server, NULL), GNUNET_MQ_handler_end () }; - static const struct GNUNET_SERVER_MessageHandler handlers[] = { - { &GNUNET_FS_handle_index_start, NULL, - GNUNET_MESSAGE_TYPE_FS_INDEX_START, 0 }, - { &GNUNET_FS_handle_index_list_get, NULL, - GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET, - sizeof (struct GNUNET_MessageHeader) }, - { &GNUNET_FS_handle_unindex, NULL, - GNUNET_MESSAGE_TYPE_FS_UNINDEX, - sizeof (struct UnindexMessage) }, - { &handle_start_search, NULL, - GNUNET_MESSAGE_TYPE_FS_START_SEARCH, 0 }, - { &handle_loc_sign, NULL, - GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN, - sizeof (struct RequestLocSignatureMessage) }, - {NULL, NULL, 0, 0} - }; int anon_p2p_off; char *keyfile; @@ -697,10 +1314,6 @@ main_init (struct GNUNET_SERVER_Handle *server, "core"); return GNUNET_SYSERR; } - GNUNET_SERVER_disconnect_notify (server, - &GSF_client_disconnect_handler_, - NULL); - GNUNET_SERVER_add_handlers (server, handlers); cover_age_task = GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, &age_cover_counters, @@ -718,22 +1331,26 @@ main_init (struct GNUNET_SERVER_Handle *server, * Process fs requests. * * @param cls closure - * @param server the initialized server * @param cfg configuration to use + * @param service the initialized service */ static void -run (void *cls, struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *cfg) +run (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_SERVICE_Handle *service) { unsigned long long dqs; GSF_cfg = cfg; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_size (GSF_cfg, "fs", "DATASTORE_QUEUE_SIZE", + GNUNET_CONFIGURATION_get_value_size (GSF_cfg, + "fs", + "DATASTORE_QUEUE_SIZE", &dqs)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO, - "fs", "DATASTORE_QUEUE_SIZE"); + "fs", + "DATASTORE_QUEUE_SIZE"); dqs = 1024; } GSF_datastore_queue_size = (unsigned int) dqs; @@ -754,11 +1371,14 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, GSF_plan_init (); GSF_pending_request_init_ (); GSF_connected_peer_init_ (); - GSF_ats = GNUNET_ATS_performance_init (GSF_cfg, &update_latencies, NULL); + GSF_ats = GNUNET_ATS_performance_init (GSF_cfg, + &update_latencies, + NULL); GSF_push_init_ (); GSF_put_init_ (); - if ((GNUNET_OK != GNUNET_FS_indexing_init (cfg, GSF_dsh)) || - (GNUNET_OK != main_init (server, cfg))) + if ( (GNUNET_OK != GNUNET_FS_indexing_init (cfg, + GSF_dsh)) || + (GNUNET_OK != main_init (cfg)) ) { GNUNET_SCHEDULER_shutdown (); shutdown_task (NULL); @@ -768,18 +1388,36 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, /** - * The main function for the fs service. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error + * Define "main" method using service macro. */ -int -main (int argc, char *const *argv) -{ - return (GNUNET_OK == - GNUNET_SERVICE_run (argc, argv, "fs", GNUNET_SERVICE_OPTION_NONE, - &run, NULL)) ? 0 : 1; -} +GNUNET_SERVICE_MAIN +("fs", + GNUNET_SERVICE_OPTION_NONE, + &run, + &client_connect_cb, + &client_disconnect_cb, + NULL, + GNUNET_MQ_hd_var_size (client_index_start, + GNUNET_MESSAGE_TYPE_FS_INDEX_START, + struct IndexStartMessage, + NULL), + GNUNET_MQ_hd_fixed_size (client_index_list_get, + GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET, + struct GNUNET_MessageHeader, + NULL), + GNUNET_MQ_hd_fixed_size (client_unindex, + GNUNET_MESSAGE_TYPE_FS_UNINDEX, + struct UnindexMessage, + NULL), + GNUNET_MQ_hd_var_size (client_start_search, + GNUNET_MESSAGE_TYPE_FS_START_SEARCH, + struct SearchMessage, + NULL), + GNUNET_MQ_hd_fixed_size (client_loc_sign, + GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN, + struct RequestLocSignatureMessage, + NULL), + GNUNET_MQ_handler_end ()); + /* end of gnunet-service-fs.c */ diff --git a/src/fs/gnunet-service-fs.h b/src/fs/gnunet-service-fs.h index 2a0f7ba29..2606565bf 100644 --- a/src/fs/gnunet-service-fs.h +++ b/src/fs/gnunet-service-fs.h @@ -307,6 +307,5 @@ void GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start); - #endif /* end of gnunet-service-fs.h */ diff --git a/src/fs/gnunet-service-fs_indexing.c b/src/fs/gnunet-service-fs_indexing.c index 385c88fe2..3ce68f487 100644 --- a/src/fs/gnunet-service-fs_indexing.c +++ b/src/fs/gnunet-service-fs_indexing.c @@ -79,6 +79,7 @@ struct IndexInfo /** * Head of linked list of indexed files. + * FIXME: we don't need both a DLL and a hashmap here! */ static struct IndexInfo *indexed_files_head; @@ -117,29 +118,38 @@ write_index_list () struct IndexInfo *pos; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) + GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", + "INDEXDB", + &fn)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "fs", "INDEXDB"); + "fs", + "INDEXDB"); return; } wh = GNUNET_BIO_write_open (fn); if (NULL == wh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - _("Could not open `%s'.\n"), fn); + _("Could not open `%s'.\n"), + fn); GNUNET_free (fn); return; } for (pos = indexed_files_head; NULL != pos; pos = pos->next) if ((GNUNET_OK != - GNUNET_BIO_write (wh, &pos->file_id, sizeof (struct GNUNET_HashCode))) || - (GNUNET_OK != GNUNET_BIO_write_string (wh, pos->filename))) + GNUNET_BIO_write (wh, + &pos->file_id, + sizeof (struct GNUNET_HashCode))) || + (GNUNET_OK != + GNUNET_BIO_write_string (wh, + pos->filename))) break; if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - _("Error writing `%s'.\n"), fn); + _("Error writing `%s'.\n"), + fn); GNUNET_free (fn); return; } @@ -162,10 +172,14 @@ read_index_list () char *emsg; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) + GNUNET_CONFIGURATION_get_value_filename (cfg, + "FS", + "INDEXDB", + &fn)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "fs", "INDEXDB"); + "fs", + "INDEXDB"); return; } if (GNUNET_NO == GNUNET_DISK_file_test (fn)) @@ -178,16 +192,22 @@ read_index_list () if (NULL == rh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - _("Could not open `%s'.\n"), fn); + _("Could not open `%s'.\n"), + fn); GNUNET_free (fn); return; } - while ((GNUNET_OK == - GNUNET_BIO_read (rh, "Hash of indexed file", &hc, - sizeof (struct GNUNET_HashCode))) && - (GNUNET_OK == - GNUNET_BIO_read_string (rh, "Name of indexed file", &fname, - 1024 * 16)) && (fname != NULL)) + while ( (GNUNET_OK == + GNUNET_BIO_read (rh, + "Hash of indexed file", + &hc, + sizeof (struct GNUNET_HashCode))) && + (GNUNET_OK == + GNUNET_BIO_read_string (rh, + "Name of indexed file", + &fname, + 1024 * 16)) && + (fname != NULL) ) { slen = strlen (fname) + 1; pos = GNUNET_malloc (sizeof (struct IndexInfo) + slen); @@ -214,250 +234,6 @@ read_index_list () } -/** - * We've validated the hash of the file we're about to index. Signal - * success to the client and update our internal data structures. - * - * @param ii the index info entry for the request - */ -static void -signal_index_ok (struct IndexInfo *ii) -{ - struct IndexInfo *ir; - if (GNUNET_SYSERR == - GNUNET_CONTAINER_multihashmap_put (ifm, &ii->file_id, - ii, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - ir = GNUNET_CONTAINER_multihashmap_get (ifm, - &ii->file_id); - GNUNET_assert (NULL != ir); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"), - ii->filename, - ir->filename); - GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, - GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); - GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); - GNUNET_free (ii); - return; - } - GNUNET_CONTAINER_DLL_insert (indexed_files_head, - indexed_files_tail, - ii); - write_index_list (); - GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, - GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); - GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); - ii->tc = NULL; -} - - -/** - * Function called once the hash computation over an - * indexed file has completed. - * - * @param cls closure, our publishing context - * @param res resulting hash, NULL on error - */ -static void -hash_for_index_val (void *cls, const struct GNUNET_HashCode * res) -{ - struct IndexInfo *ii = cls; - - ii->fhc = NULL; - if ((res == NULL) || - (0 != memcmp (res, &ii->file_id, sizeof (struct GNUNET_HashCode)))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Hash mismatch trying to index file `%s' which has hash `%s'\n"), - ii->filename, GNUNET_h2s (res)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wanted `%s'\n", - GNUNET_h2s (&ii->file_id)); - GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, - GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED); - GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); - GNUNET_free (ii); - return; - } - signal_index_ok (ii); -} - - -/** - * Handle INDEX_START-message. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -void -GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct IndexStartMessage *ism; - char *fn; - uint16_t msize; - struct IndexInfo *ii; - size_t slen; - uint64_t dev; - uint64_t ino; - uint64_t mydev; - uint64_t myino; - - msize = ntohs (message->size); - if ((msize <= sizeof (struct IndexStartMessage)) || - (((const char *) message)[msize - 1] != '\0')) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - ism = (const struct IndexStartMessage *) message; - if (0 != ism->reserved) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]); - if (fn == NULL) - { - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - dev = GNUNET_ntohll (ism->device); - ino = GNUNET_ntohll (ism->inode); - ism = (const struct IndexStartMessage *) message; - slen = strlen (fn) + 1; - ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen); - ii->filename = (const char *) &ii[1]; - GNUNET_memcpy (&ii[1], fn, slen); - ii->file_id = ism->file_id; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for file `%s'\n", - "START_INDEX", ii->filename); - ii->tc = GNUNET_SERVER_transmit_context_create (client); - mydev = 0; - myino = 0; - if (((dev != 0) || (ino != 0)) && - (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, &mydev, &myino)) && - ((dev == mydev) && (ino == myino))) - { - /* fast validation OK! */ - signal_index_ok (ii); - GNUNET_free (fn); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n", - (unsigned long long) ino, (unsigned long long) myino, - (unsigned int) dev, (unsigned int) mydev); - /* slow validation, need to hash full file (again) */ - ii->fhc = - GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, fn, - HASHING_BLOCKSIZE, &hash_for_index_val, ii); - if (ii->fhc == NULL) - hash_for_index_val (ii, NULL); - GNUNET_free (fn); -} - - -/** - * Handle INDEX_LIST_GET-message. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -void -GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_SERVER_TransmitContext *tc; - struct IndexInfoMessage *iim; - char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; - size_t slen; - const char *fn; - struct IndexInfo *pos; - - tc = GNUNET_SERVER_transmit_context_create (client); - iim = (struct IndexInfoMessage *) buf; - for (pos = indexed_files_head; NULL != pos; pos = pos->next) - { - fn = pos->filename; - slen = strlen (fn) + 1; - if (slen + sizeof (struct IndexInfoMessage) >= - GNUNET_SERVER_MAX_MESSAGE_SIZE) - { - GNUNET_break (0); - break; - } - iim->header.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY); - iim->header.size = htons (slen + sizeof (struct IndexInfoMessage)); - iim->reserved = 0; - iim->file_id = pos->file_id; - GNUNET_memcpy (&iim[1], fn, slen); - GNUNET_SERVER_transmit_context_append_message (tc, &iim->header); - } - GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, - GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END); - GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES); -} - - -/** - * Handle UNINDEX-message. - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -void -GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct UnindexMessage *um; - struct IndexInfo *pos; - struct GNUNET_SERVER_TransmitContext *tc; - int found; - - um = (const struct UnindexMessage *) message; - if (0 != um->reserved) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - found = GNUNET_NO; - for (pos = indexed_files_head; NULL != pos; pos = pos->next) - { - if (0 == memcmp (&pos->file_id, &um->file_id, sizeof (struct GNUNET_HashCode))) - { - GNUNET_CONTAINER_DLL_remove (indexed_files_head, - indexed_files_tail, - pos); - GNUNET_break (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_remove (ifm, &pos->file_id, - pos)); - GNUNET_free (pos); - found = GNUNET_YES; - break; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client requested unindexing of file `%s': %s\n", - GNUNET_h2s (&um->file_id), found ? "found" : "not found"); - if (GNUNET_YES == found) - write_index_list (); - tc = GNUNET_SERVER_transmit_context_create (client); - GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, - GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK); - GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES); -} - - /** * Continuation called from datastore's remove * function. @@ -498,9 +274,12 @@ remove_cont (void *cls, int success, * @return GNUNET_OK on success */ int -GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size, - const void *data, enum GNUNET_BLOCK_Type type, - uint32_t priority, uint32_t anonymity, +GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, + uint32_t size, + const void *data, + enum GNUNET_BLOCK_Type type, + uint32_t priority, + uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid, GNUNET_DATASTORE_DatumProcessor cont, @@ -522,69 +301,245 @@ GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t s if (size != sizeof (struct OnDemandBlock)) { GNUNET_break (0); - GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, + GNUNET_DATASTORE_remove (dsh, + key, + size, + data, + -1, + -1, &remove_cont, NULL); return GNUNET_SYSERR; } odb = (const struct OnDemandBlock *) data; off = GNUNET_ntohll (odb->offset); - ii = GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id); + ii = GNUNET_CONTAINER_multihashmap_get (ifm, + &odb->file_id); if (NULL == ii) { GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to find index %s\n", + GNUNET_h2s (&odb->file_id)); return GNUNET_SYSERR; } fn = ii->filename; if ((NULL == fn) || (0 != ACCESS (fn, R_OK))) { GNUNET_STATISTICS_update (GSF_stats, - gettext_noop - ("# index blocks removed: original file inaccessible"), - 1, GNUNET_YES); - GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, - &remove_cont, NULL); + gettext_noop ("# index blocks removed: original file inaccessible"), + 1, + GNUNET_YES); + GNUNET_DATASTORE_remove (dsh, + key, + size, + data, + -1, + -1, + &remove_cont, + NULL); return GNUNET_SYSERR; } - if ((NULL == - (fh = - GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, - GNUNET_DISK_PERM_NONE))) || - (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) || - (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof (ndata))))) + if ( (NULL == + (fh = + GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE))) || + (off != GNUNET_DISK_file_seek (fh, + off, + GNUNET_DISK_SEEK_SET)) || + (-1 == (nsize = GNUNET_DISK_file_read (fh, + ndata, + sizeof (ndata)))) ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Could not access indexed file `%s' (%s) at offset %llu: %s\n"), - GNUNET_h2s (&odb->file_id), fn, (unsigned long long) off, + _("Could not access indexed file `%s' (%s) at offset %llu: %s\n"), + GNUNET_h2s (&odb->file_id), + fn, + (unsigned long long) off, (fn == NULL) ? _("not indexed") : STRERROR (errno)); if (fh != NULL) GNUNET_DISK_file_close (fh); - GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, - &remove_cont, NULL); + GNUNET_DATASTORE_remove (dsh, + key, + size, + data, + -1, + -1, + &remove_cont, + NULL); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); - GNUNET_CRYPTO_hash (ndata, nsize, &nkey); - GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv); - GNUNET_CRYPTO_symmetric_encrypt (ndata, nsize, &skey, &iv, edata); - GNUNET_CRYPTO_hash (edata, nsize, &query); - if (0 != memcmp (&query, key, sizeof (struct GNUNET_HashCode))) + GNUNET_CRYPTO_hash (ndata, + nsize, + &nkey); + GNUNET_CRYPTO_hash_to_aes_key (&nkey, + &skey, + &iv); + GNUNET_CRYPTO_symmetric_encrypt (ndata, + nsize, + &skey, + &iv, + edata); + GNUNET_CRYPTO_hash (edata, + nsize, + &query); + if (0 != memcmp (&query, + key, + sizeof (struct GNUNET_HashCode))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Indexed file `%s' changed at offset %llu\n"), fn, + _("Indexed file `%s' changed at offset %llu\n"), + fn, (unsigned long long) off); - GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, - &remove_cont, NULL); + GNUNET_DATASTORE_remove (dsh, + key, + size, + data, + -1, + -1, + &remove_cont, + NULL); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "On-demand encoded block for query `%s'\n", GNUNET_h2s (key)); - cont (cont_cls, key, nsize, edata, GNUNET_BLOCK_TYPE_FS_DBLOCK, priority, - anonymity, expiration, uid); + "On-demand encoded block for query `%s'\n", + GNUNET_h2s (key)); + cont (cont_cls, + key, + nsize, + edata, + GNUNET_BLOCK_TYPE_FS_DBLOCK, + priority, + anonymity, + expiration, + uid); return GNUNET_OK; } +/** + * Transmit information about indexed files to @a mq. + * + * @param mq message queue to send information to + */ +void +GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq) +{ + struct GNUNET_MQ_Envelope *env; + struct IndexInfoMessage *iim; + struct GNUNET_MessageHeader *iem; + size_t slen; + const char *fn; + struct IndexInfo *pos; + + for (pos = indexed_files_head; NULL != pos; pos = pos->next) + { + fn = pos->filename; + slen = strlen (fn) + 1; + if (slen + sizeof (struct IndexInfoMessage) >= + GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + break; + } + env = GNUNET_MQ_msg_extra (iim, + slen, + GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY); + iim->reserved = 0; + iim->file_id = pos->file_id; + GNUNET_memcpy (&iim[1], + fn, + slen); + GNUNET_MQ_send (mq, + env); + } + env = GNUNET_MQ_msg (iem, + GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END); + GNUNET_MQ_send (mq, + env); +} + + +/** + * Remove a file from the index. + * + * @param fid identifier of the file to remove + * @return #GNUNET_YES if the @a fid was found + */ +int +GNUNET_FS_indexing_do_unindex (const struct GNUNET_HashCode *fid) +{ + struct IndexInfo *pos; + + for (pos = indexed_files_head; NULL != pos; pos = pos->next) + { + if (0 == memcmp (&pos->file_id, + fid, + sizeof (struct GNUNET_HashCode))) + { + GNUNET_CONTAINER_DLL_remove (indexed_files_head, + indexed_files_tail, + pos); + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (ifm, + &pos->file_id, + pos)); + GNUNET_free (pos); + write_index_list (); + return GNUNET_YES; + } + } + return GNUNET_NO; +} + + +/** + * Add the given file to the list of indexed files. + * + * @param filename name of the file + * @param file_id hash identifier for @a filename + */ +void +GNUNET_FS_add_to_index (const char *filename, + const struct GNUNET_HashCode *file_id) +{ + struct IndexInfo *ii; + size_t slen; + + ii = GNUNET_CONTAINER_multihashmap_get (ifm, + file_id); + if (NULL != ii) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"), + filename, + ii->filename); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding file %s to index as %s\n", + filename, + GNUNET_h2s (file_id)); + slen = strlen (filename) + 1; + ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen); + ii->file_id = *file_id; + ii->filename = (const char *) &ii[1]; + memcpy (&ii[1], + filename, + slen); + GNUNET_CONTAINER_DLL_insert (indexed_files_head, + indexed_files_tail, + ii); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (ifm, + &ii->file_id, + ii, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + write_index_list (); +} + + /** * Shutdown the module. */ @@ -602,7 +557,8 @@ GNUNET_FS_indexing_done () GNUNET_CRYPTO_hash_file_cancel (pos->fhc); GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (ifm, - &pos->file_id, pos)); + &pos->file_id, + pos)); GNUNET_free (pos); } GNUNET_CONTAINER_multihashmap_destroy (ifm); @@ -623,7 +579,8 @@ GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c, { cfg = c; dsh = d; - ifm = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_YES); + ifm = GNUNET_CONTAINER_multihashmap_create (128, + GNUNET_YES); read_index_list (); return GNUNET_OK; } diff --git a/src/fs/gnunet-service-fs_indexing.h b/src/fs/gnunet-service-fs_indexing.h index a2cc4a800..8b861e3f7 100644 --- a/src/fs/gnunet-service-fs_indexing.h +++ b/src/fs/gnunet-service-fs_indexing.h @@ -51,8 +51,8 @@ * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * @param cont function to call with the actual block (at most once, on success) - * @param cont_cls closure for cont - * @return GNUNET_OK on success + * @param cont_cls closure for @a cont + * @return #GNUNET_OK on success */ int GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size, @@ -63,40 +63,35 @@ GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t s GNUNET_DATASTORE_DatumProcessor cont, void *cont_cls); + /** - * Handle INDEX_START-message. + * Transmit information about indexed files to @a mq. * - * @param cls closure - * @param client identification of the client - * @param message the actual message + * @param mq message queue to send information to */ void -GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message); +GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq); /** - * Handle INDEX_LIST_GET-message. + * Remove a file from the index. * - * @param cls closure - * @param client identification of the client - * @param message the actual message + * @param fid identifier of the file to remove + * @return #GNUNET_YES if the @a fid was found */ -void -GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message); +int +GNUNET_FS_indexing_do_unindex (const struct GNUNET_HashCode *fid); /** - * Handle UNINDEX-message. + * Add the given file to the list of indexed files. * - * @param cls closure - * @param client identification of the client - * @param message the actual message + * @param filename name of the file + * @param file_id hash identifier for @a filename */ void -GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message); +GNUNET_FS_add_to_index (const char *filename, + const struct GNUNET_HashCode *file_id); /** diff --git a/src/fs/gnunet-service-fs_lc.c b/src/fs/gnunet-service-fs_lc.c index 4526c65db..9ffd6cadd 100644 --- a/src/fs/gnunet-service-fs_lc.c +++ b/src/fs/gnunet-service-fs_lc.c @@ -29,501 +29,5 @@ #include "gnunet-service-fs_pr.h" -/** - * Doubly-linked list of requests we are performing - * on behalf of the same client. - */ -struct ClientRequest -{ - - /** - * This is a doubly-linked list. - */ - struct ClientRequest *next; - - /** - * This is a doubly-linked list. - */ - struct ClientRequest *prev; - - /** - * Request this entry represents. - */ - struct GSF_PendingRequest *pr; - - /** - * Client list this request belongs to. - */ - struct GSF_LocalClient *lc; - - /** - * Task scheduled to destroy the request. - */ - struct GNUNET_SCHEDULER_Task * kill_task; - -}; - - -/** - * Replies to be transmitted to the client. The actual - * response message is allocated after this struct. - */ -struct ClientResponse -{ - /** - * This is a doubly-linked list. - */ - struct ClientResponse *next; - - /** - * This is a doubly-linked list. - */ - struct ClientResponse *prev; - - /** - * Client list entry this response belongs to. - */ - struct GSF_LocalClient *lc; - - /** - * Number of bytes in the response. - */ - size_t msize; -}; - - -/** - * A local client. - */ -struct GSF_LocalClient -{ - - /** - * We keep clients in a DLL. - */ - struct GSF_LocalClient *next; - - /** - * We keep clients in a DLL. - */ - struct GSF_LocalClient *prev; - - /** - * ID of the client. - */ - struct GNUNET_SERVER_Client *client; - - /** - * Head of list of requests performed on behalf - * of this client right now. - */ - struct ClientRequest *cr_head; - - /** - * Tail of list of requests performed on behalf - * of this client right now. - */ - struct ClientRequest *cr_tail; - - /** - * Head of linked list of responses. - */ - struct ClientResponse *res_head; - - /** - * Tail of linked list of responses. - */ - struct ClientResponse *res_tail; - - /** - * Context for sending replies. - */ - struct GNUNET_SERVER_TransmitHandle *th; - -}; - - -/** - * Head of linked list of our local clients. - */ -static struct GSF_LocalClient *client_head; - -/** - * Head of linked list of our local clients. - */ -static struct GSF_LocalClient *client_tail; - - -/** - * Look up a local client record or create one if it - * doesn't exist yet. - * - * @param client handle of the client - * @return handle to local client entry - */ -struct GSF_LocalClient * -GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client) -{ - struct GSF_LocalClient *pos; - - pos = client_head; - while ((NULL != pos) && (pos->client != client)) - pos = pos->next; - if (NULL != pos) - return pos; - pos = GNUNET_new (struct GSF_LocalClient); - pos->client = client; - GNUNET_CONTAINER_DLL_insert (client_head, - client_tail, - pos); - return pos; -} - - -/** - * Free the given client request. - * - * @param cls the client request to free - */ -static void -client_request_destroy (void *cls) -{ - struct ClientRequest *cr = cls; - struct GSF_LocalClient *lc; - - cr->kill_task = NULL; - lc = cr->lc; - GNUNET_CONTAINER_DLL_remove (lc->cr_head, - lc->cr_tail, - cr); - GSF_pending_request_cancel_ (cr->pr, - GNUNET_YES); - GNUNET_STATISTICS_update (GSF_stats, - gettext_noop ("# client searches active"), - -1, - GNUNET_NO); - GNUNET_free (cr); -} - - -/** - * Handle a reply to a pending request. Also called if a request - * expires (then with data == NULL). The handler may be called - * many times (depending on the request type), but will not be - * called during or after a call to #GSF_pending_request_cancel() - * and will also not be called anymore after a call signalling - * expiration. - * - * @param cls user-specified closure - * @param eval evaluation of the result - * @param pr handle to the original pending request - * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" - * @param expiration when does @a data expire? - * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown) - * @param type type of the block - * @param data response data, NULL on request expiration - * @param data_len number of bytes in @a data - */ -static void -client_response_handler (void *cls, - enum GNUNET_BLOCK_EvaluationResult eval, - struct GSF_PendingRequest *pr, - uint32_t reply_anonymity_level, - struct GNUNET_TIME_Absolute expiration, - struct GNUNET_TIME_Absolute last_transmission, - enum GNUNET_BLOCK_Type type, - const void *data, - size_t data_len) -{ - struct ClientRequest *cr = cls; - struct GSF_LocalClient *lc; - struct ClientPutMessage *pm; - const struct GSF_PendingRequestData *prd; - size_t msize; - - if (NULL == data) - { - /* local-only request, with no result, clean up. */ - if (NULL == cr->kill_task) - cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, - cr); - return; - } - prd = GSF_pending_request_get_data_ (pr); - GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY); - if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY)) - { - GNUNET_break (0); - return; - } - GNUNET_STATISTICS_update (GSF_stats, - gettext_noop - ("# replies received for local clients"), 1, - GNUNET_NO); - GNUNET_assert (pr == cr->pr); - lc = cr->lc; - msize = sizeof (struct ClientPutMessage) + data_len; - { - char buf[msize] GNUNET_ALIGN; - - pm = (struct ClientPutMessage *) buf; - pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT); - pm->header.size = htons (msize); - pm->type = htonl (type); - pm->expiration = GNUNET_TIME_absolute_hton (expiration); - pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission); - pm->num_transmissions = htonl (prd->num_transmissions); - pm->respect_offered = htonl (prd->respect_offered); - GNUNET_memcpy (&pm[1], data, data_len); - GSF_local_client_transmit_ (lc, &pm->header); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Queued reply to query `%s' for local client\n", - GNUNET_h2s (&prd->query)); - if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Evaluation %d - keeping query alive\n", - (int) eval); - return; - } - if (NULL == cr->kill_task) - cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, cr); -} - - -/** - * Handle START_SEARCH-message (search request from local client). - * Only responsible for creating the request entry itself and setting - * up reply callback and cancellation on client disconnect. Does NOT - * execute the actual request strategy (planning). - * - * @param client identification of the client - * @param message the actual message - * @param prptr where to store the pending request handle for the request - * @return #GNUNET_YES to start local processing, - * #GNUNET_NO to not (yet) start local processing, - * #GNUNET_SYSERR on error - */ -int -GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message, - struct GSF_PendingRequest **prptr) -{ - static struct GNUNET_PeerIdentity all_zeros; - const struct SearchMessage *sm; - struct GSF_LocalClient *lc; - struct ClientRequest *cr; - struct GSF_PendingRequestData *prd; - uint16_t msize; - unsigned int sc; - enum GNUNET_BLOCK_Type type; - enum GSF_PendingRequestOptions options; - - msize = ntohs (message->size); - if ((msize < sizeof (struct SearchMessage)) || - (0 != (msize - sizeof (struct SearchMessage)) % sizeof (struct GNUNET_HashCode))) - { - GNUNET_break (0); - *prptr = NULL; - return GNUNET_SYSERR; - } - GNUNET_STATISTICS_update (GSF_stats, - gettext_noop ("# client searches received"), - 1, - GNUNET_NO); - sc = (msize - sizeof (struct SearchMessage)) / sizeof (struct GNUNET_HashCode); - sm = (const struct SearchMessage *) message; - type = ntohl (sm->type); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received request for `%s' of type %u from local client\n", - GNUNET_h2s (&sm->query), (unsigned int) type); - lc = GSF_local_client_lookup_ (client); - cr = NULL; - /* detect duplicate UBLOCK requests */ - if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) || - (type == GNUNET_BLOCK_TYPE_ANY)) - { - cr = lc->cr_head; - while (NULL != cr) - { - prd = GSF_pending_request_get_data_ (cr->pr); - /* only unify with queries that hae not yet started local processing - (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a - matching query and type */ - if ((GNUNET_YES != prd->has_started) && - (0 != memcmp (&prd->query, - &sm->query, - sizeof (struct GNUNET_HashCode))) && - (prd->type == type)) - break; - cr = cr->next; - } - } - if (NULL != cr) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Have existing request, merging content-seen lists.\n"); - GSF_pending_request_update_ (cr->pr, - (const struct GNUNET_HashCode *) &sm[1], - sc); - GNUNET_STATISTICS_update (GSF_stats, - gettext_noop - ("# client searches updated (merged content seen list)"), - 1, GNUNET_NO); - } - else - { - GNUNET_STATISTICS_update (GSF_stats, - gettext_noop ("# client searches active"), 1, - GNUNET_NO); - cr = GNUNET_new (struct ClientRequest); - cr->lc = lc; - GNUNET_CONTAINER_DLL_insert (lc->cr_head, - lc->cr_tail, - cr); - options = GSF_PRO_LOCAL_REQUEST; - if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options))) - options |= GSF_PRO_LOCAL_ONLY; - cr->pr = GSF_pending_request_create_ (options, type, - &sm->query, - (0 != - memcmp (&sm->target, &all_zeros, - sizeof (struct GNUNET_PeerIdentity))) - ? &sm->target : NULL, NULL, 0, - 0 /* bf */ , - ntohl (sm->anonymity_level), - 0 /* priority */ , - 0 /* ttl */ , - 0 /* sender PID */ , - 0 /* origin PID */ , - (const struct GNUNET_HashCode *) &sm[1], sc, - &client_response_handler, cr); - } - *prptr = cr->pr; - return (0 != - (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options))) ? GNUNET_NO : - GNUNET_YES; -} - - -/** - * Transmit the given message by copying it to the target buffer - * "buf". "buf" will be NULL and "size" zero if the socket was closed - * for writing in the meantime. In that case, do nothing - * (the disconnect or shutdown handler will take care of the rest). - * If we were able to transmit messages and there are still more - * pending, ask core again for further calls to this function. - * - * @param cls closure, pointer to the `struct GSF_LocalClient` - * @param size number of bytes available in @a buf - * @param buf where the callee should write the message - * @return number of bytes written to @a buf - */ -static size_t -transmit_to_client (void *cls, - size_t size, - void *buf) -{ - struct GSF_LocalClient *lc = cls; - char *cbuf = buf; - struct ClientResponse *res; - size_t msize; - - lc->th = NULL; - if (NULL == buf) - return 0; - msize = 0; - while ((NULL != (res = lc->res_head)) && (res->msize <= size)) - { - GNUNET_memcpy (&cbuf[msize], &res[1], res->msize); - msize += res->msize; - size -= res->msize; - GNUNET_CONTAINER_DLL_remove (lc->res_head, lc->res_tail, res); - GNUNET_free (res); - } - if (NULL != res) - lc->th = - GNUNET_SERVER_notify_transmit_ready (lc->client, res->msize, - GNUNET_TIME_UNIT_FOREVER_REL, - &transmit_to_client, lc); - return msize; -} - - -/** - * Transmit a message to the given local client as soon as possible. - * If the client disconnects before transmission, the message is - * simply discarded. - * - * @param lc recipient - * @param msg message to transmit to client - */ -void -GSF_local_client_transmit_ (struct GSF_LocalClient *lc, - const struct GNUNET_MessageHeader *msg) -{ - struct ClientResponse *res; - size_t msize; - - msize = ntohs (msg->size); - res = GNUNET_malloc (sizeof (struct ClientResponse) + msize); - res->lc = lc; - res->msize = msize; - GNUNET_memcpy (&res[1], - msg, - msize); - GNUNET_CONTAINER_DLL_insert_tail (lc->res_head, - lc->res_tail, - res); - if (NULL == lc->th) - lc->th = - GNUNET_SERVER_notify_transmit_ready (lc->client, msize, - GNUNET_TIME_UNIT_FOREVER_REL, - &transmit_to_client, lc); -} - - -/** - * A client disconnected from us. Tear down the local client - * record. - * - * @param cls unused - * @param client handle of the client - */ -void -GSF_client_disconnect_handler_ (void *cls, - struct GNUNET_SERVER_Client *client) -{ - struct GSF_LocalClient *pos; - struct ClientRequest *cr; - struct ClientResponse *res; - - pos = client_head; - while ((pos != NULL) && (pos->client != client)) - pos = pos->next; - if (NULL == pos) - return; - while (NULL != (cr = pos->cr_head)) - { - if (NULL != cr->kill_task) - GNUNET_SCHEDULER_cancel (cr->kill_task); - client_request_destroy (cr); - } - while (NULL != (res = pos->res_head)) - { - GNUNET_CONTAINER_DLL_remove (pos->res_head, pos->res_tail, res); - GNUNET_free (res); - } - if (NULL != pos->th) - { - GNUNET_SERVER_notify_transmit_ready_cancel (pos->th); - pos->th = NULL; - } - GSF_handle_local_client_disconnect_ (pos); - GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos); - GNUNET_free (pos); -} - /* end of gnunet-service-fs_lc.c */ diff --git a/src/fs/gnunet-service-fs_lc.h b/src/fs/gnunet-service-fs_lc.h index c06166685..6671ed33c 100644 --- a/src/fs/gnunet-service-fs_lc.h +++ b/src/fs/gnunet-service-fs_lc.h @@ -29,59 +29,5 @@ #include "gnunet-service-fs.h" -/** - * Look up a local client record or create one if it - * doesn't exist yet. - * - * @param client handle of the client - * @return handle to local client entry - */ -struct GSF_LocalClient * -GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client); - - -/** - * Handle START_SEARCH-message (search request from local client). - * Only responsible for creating the request entry itself and setting - * up reply callback and cancellation on client disconnect. Does NOT - * execute the actual request strategy (planning). - * - * @param client identification of the client - * @param message the actual message - * @param prptr where to store the pending request handle for the request - * @return GNUNET_YES to start local processing, - * GNUNET_NO to not (yet) start local processing, - * GNUNET_SYSERR on error - */ -int -GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader - *message, - struct GSF_PendingRequest **prptr); - - -/** - * Transmit a message to the given local client as soon as possible. - * If the client disconnects before transmission, the message is - * simply discarded. - * - * @param lc recipient - * @param msg message to transmit to client - */ -void -GSF_local_client_transmit_ (struct GSF_LocalClient *lc, - const struct GNUNET_MessageHeader *msg); - - -/** - * A client disconnected from us. Tear down the local client record. - * - * @param cls unused - * @param client handle of the client - */ -void -GSF_client_disconnect_handler_ (void *cls, struct GNUNET_SERVER_Client *client); - - #endif /* end of gnunet-service-fs_lc.h */