aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-10-01 12:53:07 +0000
committerChristian Grothoff <christian@grothoff.org>2016-10-01 12:53:07 +0000
commitf7fac7f6736df4e350a8b5ed7d9f51782d7e039e (patch)
tree6eee38f2dbc4de932c22d213dde60cf06992b127 /src
parent760f75d2d87f01ca93ebfb349eedbb4224c03c7c (diff)
downloadgnunet-f7fac7f6736df4e350a8b5ed7d9f51782d7e039e.tar.gz
gnunet-f7fac7f6736df4e350a8b5ed7d9f51782d7e039e.zip
migrating fs to new service API
Diffstat (limited to 'src')
-rw-r--r--src/fs/Makefile.am1
-rw-r--r--src/fs/gnunet-service-fs.c850
-rw-r--r--src/fs/gnunet-service-fs.h1
-rw-r--r--src/fs/gnunet-service-fs_indexing.c543
-rw-r--r--src/fs/gnunet-service-fs_indexing.h37
-rw-r--r--src/fs/gnunet-service-fs_lc.c496
-rw-r--r--src/fs/gnunet-service-fs_lc.h54
7 files changed, 1010 insertions, 972 deletions
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 = \
190 gnunet-service-fs.c gnunet-service-fs.h \ 190 gnunet-service-fs.c gnunet-service-fs.h \
191 gnunet-service-fs_cp.c gnunet-service-fs_cp.h \ 191 gnunet-service-fs_cp.c gnunet-service-fs_cp.h \
192 gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \ 192 gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \
193 gnunet-service-fs_lc.c gnunet-service-fs_lc.h \
194 gnunet-service-fs_pe.c gnunet-service-fs_pe.h \ 193 gnunet-service-fs_pe.c gnunet-service-fs_pe.h \
195 gnunet-service-fs_pr.c gnunet-service-fs_pr.h \ 194 gnunet-service-fs_pr.c gnunet-service-fs_pr.h \
196 gnunet-service-fs_push.c gnunet-service-fs_push.h \ 195 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 @@
68#define INSANE_STATISTICS GNUNET_NO 68#define INSANE_STATISTICS GNUNET_NO
69 69
70 70
71
72/**
73 * Doubly-linked list of requests we are performing
74 * on behalf of the same client.
75 */
76struct ClientRequest
77{
78
79 /**
80 * This is a doubly-linked list.
81 */
82 struct ClientRequest *next;
83
84 /**
85 * This is a doubly-linked list.
86 */
87 struct ClientRequest *prev;
88
89 /**
90 * Request this entry represents.
91 */
92 struct GSF_PendingRequest *pr;
93
94 /**
95 * Client list this request belongs to.
96 */
97 struct GSF_LocalClient *lc;
98
99 /**
100 * Task scheduled to destroy the request.
101 */
102 struct GNUNET_SCHEDULER_Task * kill_task;
103
104};
105
106
107/**
108 * Replies to be transmitted to the client. The actual
109 * response message is allocated after this struct.
110 */
111struct ClientResponse
112{
113 /**
114 * This is a doubly-linked list.
115 */
116 struct ClientResponse *next;
117
118 /**
119 * This is a doubly-linked list.
120 */
121 struct ClientResponse *prev;
122
123 /**
124 * Client list entry this response belongs to.
125 */
126 struct GSF_LocalClient *lc;
127
128 /**
129 * Number of bytes in the response.
130 */
131 size_t msize;
132};
133
134
135/**
136 * Information we track while handling an index
137 * start request from a client.
138 */
139struct IndexStartContext
140{
141
142 /**
143 * This is a doubly linked list.
144 */
145 struct IndexStartContext *next;
146
147 /**
148 * This is a doubly linked list.
149 */
150 struct IndexStartContext *prev;
151
152 /**
153 * Name of the indexed file.
154 */
155 char *filename;
156
157 /**
158 * Context for transmitting confirmation to client.
159 */
160 struct GSF_LocalClient *lc;
161
162 /**
163 * Context for hashing of the file.
164 */
165 struct GNUNET_CRYPTO_FileHashContext *fhc;
166
167 /**
168 * Hash of the contents of the file.
169 */
170 struct GNUNET_HashCode file_id;
171
172};
173
174
175/**
176 * A local client.
177 */
178struct GSF_LocalClient
179{
180
181 /**
182 * ID of the client.
183 */
184 struct GNUNET_SERVICE_Client *client;
185
186 /**
187 * Queue for sending replies.
188 */
189 struct GNUNET_MQ_Handle *mq;
190
191 /**
192 * Head of list of requests performed on behalf
193 * of this client right now.
194 */
195 struct ClientRequest *cr_head;
196
197 /**
198 * Tail of list of requests performed on behalf
199 * of this client right now.
200 */
201 struct ClientRequest *cr_tail;
202
203 /**
204 * This is a doubly linked list.
205 */
206 struct IndexStartContext *isc_head;
207
208 /**
209 * This is a doubly linked list.
210 */
211 struct IndexStartContext *isc_tail;
212
213 /**
214 * Head of linked list of responses.
215 */
216 struct ClientResponse *res_head;
217
218 /**
219 * Tail of linked list of responses.
220 */
221 struct ClientResponse *res_tail;
222
223};
224
225
71/* ****************************** globals ****************************** */ 226/* ****************************** globals ****************************** */
72 227
73/** 228/**
@@ -152,6 +307,11 @@ struct GNUNET_CORE_Handle *GSF_core;
152 */ 307 */
153int GSF_enable_randomized_delays; 308int GSF_enable_randomized_delays;
154 309
310/**
311 * Identity of this peer.
312 */
313struct GNUNET_PeerIdentity GSF_my_id;
314
155/* ***************************** locals ******************************* */ 315/* ***************************** locals ******************************* */
156 316
157/** 317/**
@@ -174,10 +334,183 @@ static struct GNUNET_SCHEDULER_Task * cover_age_task;
174 */ 334 */
175static struct GNUNET_LOAD_Value *datastore_get_load; 335static struct GNUNET_LOAD_Value *datastore_get_load;
176 336
337
177/** 338/**
178 * Identity of this peer. 339 * Creates a fresh local client handle.
340 *
341 * @param cls NULL
342 * @param client handle of the client
343 * @param mq message queue for @a client
344 * @return handle to local client entry
179 */ 345 */
180struct GNUNET_PeerIdentity GSF_my_id; 346static void *
347client_connect_cb (void *cls,
348 struct GNUNET_SERVICE_Client *client,
349 struct GNUNET_MQ_Handle *mq)
350{
351 struct GSF_LocalClient *pos;
352
353 pos = GNUNET_new (struct GSF_LocalClient);
354 pos->client = client;
355 pos->mq = mq;
356 return pos;
357}
358
359
360/**
361 * Free the given client request.
362 *
363 * @param cls the client request to free
364 */
365static void
366client_request_destroy (void *cls)
367{
368 struct ClientRequest *cr = cls;
369 struct GSF_LocalClient *lc = cr->lc;
370
371 cr->kill_task = NULL;
372 GNUNET_CONTAINER_DLL_remove (lc->cr_head,
373 lc->cr_tail,
374 cr);
375 GSF_pending_request_cancel_ (cr->pr,
376 GNUNET_YES);
377 GNUNET_STATISTICS_update (GSF_stats,
378 gettext_noop ("# client searches active"),
379 -1,
380 GNUNET_NO);
381 GNUNET_free (cr);
382}
383
384
385/**
386 * Handle a reply to a pending request. Also called if a request
387 * expires (then with data == NULL). The handler may be called
388 * many times (depending on the request type), but will not be
389 * called during or after a call to #GSF_pending_request_cancel()
390 * and will also not be called anymore after a call signalling
391 * expiration.
392 *
393 * @param cls user-specified closure
394 * @param eval evaluation of the result
395 * @param pr handle to the original pending request
396 * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
397 * @param expiration when does @a data expire?
398 * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
399 * @param type type of the block
400 * @param data response data, NULL on request expiration
401 * @param data_len number of bytes in @a data
402 */
403static void
404client_response_handler (void *cls,
405 enum GNUNET_BLOCK_EvaluationResult eval,
406 struct GSF_PendingRequest *pr,
407 uint32_t reply_anonymity_level,
408 struct GNUNET_TIME_Absolute expiration,
409 struct GNUNET_TIME_Absolute last_transmission,
410 enum GNUNET_BLOCK_Type type,
411 const void *data,
412 size_t data_len)
413{
414 struct ClientRequest *cr = cls;
415 struct GSF_LocalClient *lc;
416 struct GNUNET_MQ_Envelope *env;
417 struct ClientPutMessage *pm;
418 const struct GSF_PendingRequestData *prd;
419
420 if (NULL == data)
421 {
422 /* local-only request, with no result, clean up. */
423 if (NULL == cr->kill_task)
424 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
425 cr);
426 return;
427 }
428 prd = GSF_pending_request_get_data_ (pr);
429 GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY);
430 if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
431 {
432 GNUNET_break (0);
433 return;
434 }
435 GNUNET_STATISTICS_update (GSF_stats,
436 gettext_noop
437 ("# replies received for local clients"), 1,
438 GNUNET_NO);
439 GNUNET_assert (pr == cr->pr);
440 lc = cr->lc;
441 env = GNUNET_MQ_msg_extra (pm,
442 data_len,
443 GNUNET_MESSAGE_TYPE_FS_PUT);
444 pm->type = htonl (type);
445 pm->expiration = GNUNET_TIME_absolute_hton (expiration);
446 pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
447 pm->num_transmissions = htonl (prd->num_transmissions);
448 pm->respect_offered = htonl (prd->respect_offered);
449 GNUNET_memcpy (&pm[1],
450 data,
451 data_len);
452 GNUNET_MQ_send (lc->mq,
453 env);
454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455 "Queued reply to query `%s' for local client\n",
456 GNUNET_h2s (&prd->query));
457 if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval)
458 {
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Evaluation %d - keeping query alive\n",
461 (int) eval);
462 return;
463 }
464 if (NULL == cr->kill_task)
465 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
466 cr);
467}
468
469
470/**
471 * A client disconnected from us. Tear down the local client
472 * record.
473 *
474 * @param cls unused
475 * @param client handle of the client
476 * @param app_ctx the `struct GSF_LocalClient`
477 */
478static void
479client_disconnect_cb (void *cls,
480 struct GNUNET_SERVICE_Client *client,
481 void *app_ctx)
482{
483 struct GSF_LocalClient *lc = app_ctx;
484 struct IndexStartContext *isc;
485 struct ClientRequest *cr;
486 struct ClientResponse *res;
487
488 while (NULL != (cr = lc->cr_head))
489 {
490 if (NULL != cr->kill_task)
491 GNUNET_SCHEDULER_cancel (cr->kill_task);
492 client_request_destroy (cr);
493 }
494 while (NULL != (res = lc->res_head))
495 {
496 GNUNET_CONTAINER_DLL_remove (lc->res_head,
497 lc->res_tail,
498 res);
499 GNUNET_free (res);
500 }
501 while (NULL != (isc = lc->isc_head))
502 {
503 GNUNET_CONTAINER_DLL_remove (lc->isc_head,
504 lc->isc_tail,
505 isc);
506 GNUNET_CRYPTO_hash_file_cancel (isc->fhc);
507 GNUNET_free (isc);
508 }
509 GNUNET_free (lc);
510}
511
512
513
181 514
182 515
183/** 516/**
@@ -289,7 +622,7 @@ check_p2p_put (void *cls,
289 const struct PutMessage *put) 622 const struct PutMessage *put)
290{ 623{
291 enum GNUNET_BLOCK_Type type; 624 enum GNUNET_BLOCK_Type type;
292 625
293 type = ntohl (put->type); 626 type = ntohl (put->type);
294 if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type) 627 if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
295 { 628 {
@@ -373,7 +706,7 @@ check_p2p_get (void *cls,
373 unsigned int bm; 706 unsigned int bm;
374 unsigned int bits; 707 unsigned int bits;
375 size_t bfsize; 708 size_t bfsize;
376 709
377 msize = ntohs (gm->header.size); 710 msize = ntohs (gm->header.size);
378 bm = ntohl (gm->hash_bitmap); 711 bm = ntohl (gm->hash_bitmap);
379 bits = 0; 712 bits = 0;
@@ -394,8 +727,8 @@ check_p2p_get (void *cls,
394 { 727 {
395 GNUNET_break_op (0); 728 GNUNET_break_op (0);
396 return GNUNET_SYSERR; 729 return GNUNET_SYSERR;
397 } 730 }
398 return GNUNET_OK; 731 return GNUNET_OK;
399} 732}
400 733
401 734
@@ -405,7 +738,7 @@ check_p2p_get (void *cls,
405 * result status). Also signal that we can now 738 * result status). Also signal that we can now
406 * receive more request information from the client. 739 * receive more request information from the client.
407 * 740 *
408 * @param cls the client doing the request (`struct GNUNET_SERVER_Client`) 741 * @param cls the client doing the request (`struct GSF_LocalClient`)
409 * @param pr the pending request we were processing 742 * @param pr the pending request we were processing
410 * @param result final datastore lookup result 743 * @param result final datastore lookup result
411 */ 744 */
@@ -414,11 +747,10 @@ start_p2p_processing (void *cls,
414 struct GSF_PendingRequest *pr, 747 struct GSF_PendingRequest *pr,
415 enum GNUNET_BLOCK_EvaluationResult result) 748 enum GNUNET_BLOCK_EvaluationResult result)
416{ 749{
417 struct GNUNET_SERVER_Client *client = cls; 750 struct GSF_LocalClient *lc = cls;
418 struct GSF_PendingRequestData *prd; 751 struct GSF_PendingRequestData *prd;
419 752
420 GNUNET_SERVER_receive_done (client, 753 GNUNET_SERVICE_client_continue (lc->client);
421 GNUNET_OK);
422 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result) 754 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
423 return; /* we're done, 'pr' was already destroyed... */ 755 return; /* we're done, 'pr' was already destroyed... */
424 prd = GSF_pending_request_get_data_ (pr); 756 prd = GSF_pending_request_get_data_ (pr);
@@ -448,7 +780,33 @@ start_p2p_processing (void *cls,
448 break; 780 break;
449 } 781 }
450 } 782 }
451 GSF_consider_forwarding (NULL, pr, result); 783 GSF_consider_forwarding (NULL,
784 pr,
785 result);
786}
787
788
789/**
790 * Check #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
791 * from client).
792 *
793 * @param cls identification of the client
794 * @param sm the actual message
795 * @return #GNUNET_OK if @a sm is well-formed
796 */
797static int
798check_client_start_search (void *cls,
799 const struct SearchMessage *sm)
800{
801 uint16_t msize;
802
803 msize = ntohs (sm->header.size) - sizeof (struct SearchMessage);
804 if (0 != msize % sizeof (struct GNUNET_HashCode))
805 {
806 GNUNET_break (0);
807 return GNUNET_SYSERR;
808 }
809 return GNUNET_OK;
452} 810}
453 811
454 812
@@ -456,63 +814,128 @@ start_p2p_processing (void *cls,
456 * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request 814 * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
457 * from client). 815 * from client).
458 * 816 *
459 * @param cls closure 817 * Responsible for creating the request entry itself and setting
460 * @param client identification of the client 818 * up reply callback and cancellation on client disconnect.
461 * @param message the actual message 819 *
820 * @param cls identification of the client
821 * @param sm the actual message
462 */ 822 */
463static void 823static void
464handle_start_search (void *cls, 824handle_client_start_search (void *cls,
465 struct GNUNET_SERVER_Client *client, 825 const struct SearchMessage *sm)
466 const struct GNUNET_MessageHeader *message)
467{ 826{
468 struct GSF_PendingRequest *pr; 827 static struct GNUNET_PeerIdentity all_zeros;
469 int ret; 828 struct GSF_LocalClient *lc = cls;
470 829 struct ClientRequest *cr;
471 pr = NULL; 830 struct GSF_PendingRequestData *prd;
472 ret = GSF_local_client_start_search_handler_ (client, 831 uint16_t msize;
473 message, 832 unsigned int sc;
474 &pr); 833 enum GNUNET_BLOCK_Type type;
475 switch (ret) 834 enum GSF_PendingRequestOptions options;
476 { 835
477 case GNUNET_SYSERR: 836 GNUNET_STATISTICS_update (GSF_stats,
478 GNUNET_SERVER_receive_done (client, 837 gettext_noop ("# client searches received"),
479 GNUNET_SYSERR); 838 1,
480 break; 839 GNUNET_NO);
481 case GNUNET_NO: 840 msize = ntohs (sm->header.size) - sizeof (struct SearchMessage);
482 GNUNET_SERVER_receive_done (client, 841 sc = msize / sizeof (struct GNUNET_HashCode);
483 GNUNET_OK); 842 type = ntohl (sm->type);
484 break; 843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485 case GNUNET_YES: 844 "Received request for `%s' of type %u from local client\n",
486 GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES; 845 GNUNET_h2s (&sm->query),
487 GSF_local_lookup_ (pr, 846 (unsigned int) type);
488 &start_p2p_processing, 847 cr = NULL;
489 client); 848 /* detect duplicate UBLOCK requests */
490 break; 849 if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) ||
491 default: 850 (type == GNUNET_BLOCK_TYPE_ANY))
492 GNUNET_assert (0); 851 {
852 cr = lc->cr_head;
853 while (NULL != cr)
854 {
855 prd = GSF_pending_request_get_data_ (cr->pr);
856 /* only unify with queries that hae not yet started local processing
857 (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a
858 matching query and type */
859 if ((GNUNET_YES != prd->has_started) &&
860 (0 != memcmp (&prd->query,
861 &sm->query,
862 sizeof (struct GNUNET_HashCode))) &&
863 (prd->type == type))
864 break;
865 cr = cr->next;
866 }
867 }
868 if (NULL != cr)
869 {
870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
871 "Have existing request, merging content-seen lists.\n");
872 GSF_pending_request_update_ (cr->pr,
873 (const struct GNUNET_HashCode *) &sm[1],
874 sc);
875 GNUNET_STATISTICS_update (GSF_stats,
876 gettext_noop ("# client searches updated (merged content seen list)"),
877 1,
878 GNUNET_NO);
879 }
880 else
881 {
882 GNUNET_STATISTICS_update (GSF_stats,
883 gettext_noop ("# client searches active"),
884 1,
885 GNUNET_NO);
886 cr = GNUNET_new (struct ClientRequest);
887 cr->lc = lc;
888 GNUNET_CONTAINER_DLL_insert (lc->cr_head,
889 lc->cr_tail,
890 cr);
891 options = GSF_PRO_LOCAL_REQUEST;
892 if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options)))
893 options |= GSF_PRO_LOCAL_ONLY;
894 cr->pr = GSF_pending_request_create_ (options, type,
895 &sm->query,
896 (0 !=
897 memcmp (&sm->target,
898 &all_zeros,
899 sizeof (struct GNUNET_PeerIdentity)))
900 ? &sm->target : NULL, NULL, 0,
901 0 /* bf */ ,
902 ntohl (sm->anonymity_level),
903 0 /* priority */ ,
904 0 /* ttl */ ,
905 0 /* sender PID */ ,
906 0 /* origin PID */ ,
907 (const struct GNUNET_HashCode *) &sm[1], sc,
908 &client_response_handler,
909 cr);
493 } 910 }
911 if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options)))
912 {
913 GNUNET_SERVICE_client_continue (lc->client);
914 return;
915 }
916 GSF_pending_request_get_data_ (cr->pr)->has_started = GNUNET_YES;
917 GSF_local_lookup_ (cr->pr,
918 &start_p2p_processing,
919 lc);
494} 920}
495 921
496 922
497/** 923/**
498 * Handle request to sign a LOC URI (from client). 924 * Handle request to sign a LOC URI (from client).
499 * 925 *
500 * @param cls closure (NULL) 926 * @param cls identification of the client
501 * @param client identification of the client 927 * @param msg the actual message
502 * @param message the actual message
503 */ 928 */
504static void 929static void
505handle_loc_sign (void *cls, 930handle_client_loc_sign (void *cls,
506 struct GNUNET_SERVER_Client *client, 931 const struct RequestLocSignatureMessage *msg)
507 const struct GNUNET_MessageHeader *message)
508{ 932{
509 const struct RequestLocSignatureMessage *msg; 933 struct GSF_LocalClient *lc = cls;
510 struct GNUNET_FS_Uri base; 934 struct GNUNET_FS_Uri base;
511 struct GNUNET_FS_Uri *loc; 935 struct GNUNET_FS_Uri *loc;
512 struct ResponseLocSignatureMessage resp; 936 struct GNUNET_MQ_Envelope *env;
513 struct GSF_LocalClient *lc; 937 struct ResponseLocSignatureMessage *resp;
514 938
515 msg = (const struct RequestLocSignatureMessage *) message;
516 GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT == 939 GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT ==
517 ntohl (msg->purpose)); 940 ntohl (msg->purpose));
518 base.type = GNUNET_FS_URI_CHK; 941 base.type = GNUNET_FS_URI_CHK;
@@ -521,17 +944,228 @@ handle_loc_sign (void *cls,
521 loc = GNUNET_FS_uri_loc_create (&base, 944 loc = GNUNET_FS_uri_loc_create (&base,
522 pk, 945 pk,
523 GNUNET_TIME_absolute_ntoh (msg->expiration_time)); 946 GNUNET_TIME_absolute_ntoh (msg->expiration_time));
524 resp.header.size = htons (sizeof (struct ResponseLocSignatureMessage)); 947 env = GNUNET_MQ_msg (resp,
525 resp.header.type = htons (GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE); 948 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE);
526 resp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); 949 resp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
527 resp.expiration_time = GNUNET_TIME_absolute_hton (loc->data.loc.expirationTime); 950 resp->expiration_time = GNUNET_TIME_absolute_hton (loc->data.loc.expirationTime);
528 resp.signature = loc->data.loc.contentSignature; 951 resp->signature = loc->data.loc.contentSignature;
529 resp.peer = loc->data.loc.peer; 952 resp->peer = loc->data.loc.peer;
530 GNUNET_FS_uri_destroy (loc); 953 GNUNET_FS_uri_destroy (loc);
531 lc = GSF_local_client_lookup_ (client); 954 GNUNET_MQ_send (lc->mq,
532 GSF_local_client_transmit_ (lc, 955 env);
533 &resp.header); 956 GNUNET_SERVICE_client_continue (lc->client);
534 GNUNET_SERVER_receive_done (client, GNUNET_OK); 957}
958
959
960/**
961 * Check INDEX_START-message.
962 *
963 * @param cls identification of the client
964 * @param ism the actual message
965 * @return #GNUNET_OK if @a ism is well-formed
966 */
967static int
968check_client_index_start (void *cls,
969 const struct IndexStartMessage *ism)
970{
971 uint16_t msize;
972 char *fn;
973
974 msize = ntohs (ism->header.size);
975 if (((const char *) ism)[msize - 1] != '\0')
976 {
977 GNUNET_break (0);
978 return GNUNET_SYSERR;
979 }
980 if (0 != ism->reserved)
981 {
982 GNUNET_break (0);
983 return GNUNET_SYSERR;
984 }
985 fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
986 if (NULL == fn)
987 {
988 GNUNET_break (0);
989 return GNUNET_SYSERR;
990 }
991 GNUNET_free (fn);
992 return GNUNET_OK;
993}
994
995
996/**
997 * We've validated the hash of the file we're about to index. Signal
998 * success to the client and update our internal data structures.
999 *
1000 * @param isc the data about the index info entry for the request
1001 */
1002static void
1003signal_index_ok (struct IndexStartContext *isc)
1004{
1005 struct GSF_LocalClient *lc = isc->lc;
1006 struct GNUNET_MQ_Envelope *env;
1007 struct GNUNET_MessageHeader *msg;
1008
1009 GNUNET_FS_add_to_index (isc->filename,
1010 &isc->file_id);
1011 env = GNUNET_MQ_msg (msg,
1012 GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
1013 GNUNET_MQ_send (lc->mq,
1014 env);
1015 GNUNET_free (isc->filename);
1016 GNUNET_free (isc);
1017 GNUNET_SERVICE_client_continue (lc->client);
1018}
1019
1020
1021/**
1022 * Function called once the hash computation over an
1023 * indexed file has completed.
1024 *
1025 * @param cls closure, our publishing context
1026 * @param res resulting hash, NULL on error
1027 */
1028static void
1029hash_for_index_val (void *cls,
1030 const struct GNUNET_HashCode *res)
1031{
1032 struct IndexStartContext *isc = cls;
1033 struct GSF_LocalClient *lc = isc->lc;
1034 struct GNUNET_MQ_Envelope *env;
1035 struct GNUNET_MessageHeader *msg;
1036
1037 GNUNET_CONTAINER_DLL_remove (lc->isc_head,
1038 lc->isc_tail,
1039 isc);
1040 isc->fhc = NULL;
1041 if ( (NULL == res) ||
1042 (0 != memcmp (res,
1043 &isc->file_id,
1044 sizeof (struct GNUNET_HashCode))))
1045 {
1046 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1047 _("Hash mismatch trying to index file `%s' which does not have hash `%s'\n"),
1048 isc->filename,
1049 GNUNET_h2s (&isc->file_id));
1050 env = GNUNET_MQ_msg (msg,
1051 GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED);
1052 GNUNET_MQ_send (lc->mq,
1053 env);
1054 GNUNET_SERVICE_client_continue (lc->client);
1055 GNUNET_free (isc);
1056 return;
1057 }
1058 signal_index_ok (isc);
1059}
1060
1061
1062/**
1063 * Handle INDEX_START-message.
1064 *
1065 * @param cls identification of the client
1066 * @param message the actual message
1067 */
1068static void
1069handle_client_index_start (void *cls,
1070 const struct IndexStartMessage *ism)
1071{
1072 struct GSF_LocalClient *lc = cls;
1073 struct IndexStartContext *isc;
1074 char *fn;
1075 uint64_t dev;
1076 uint64_t ino;
1077 uint64_t mydev;
1078 uint64_t myino;
1079
1080 fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
1081 GNUNET_assert (NULL != fn);
1082 dev = GNUNET_ntohll (ism->device);
1083 ino = GNUNET_ntohll (ism->inode);
1084 isc = GNUNET_new (struct IndexStartContext);
1085 isc->filename = fn;
1086 isc->file_id = ism->file_id;
1087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1088 "Received START_INDEX message for file `%s'\n",
1089 isc->filename);
1090 isc->lc = lc;
1091 mydev = 0;
1092 myino = 0;
1093 if ( ( (dev != 0) ||
1094 (ino != 0) ) &&
1095 (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn,
1096 &mydev,
1097 &myino)) &&
1098 (dev == mydev) &&
1099 (ino == myino) )
1100 {
1101 /* fast validation OK! */
1102 signal_index_ok (isc);
1103 return;
1104 }
1105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1106 "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n",
1107 (unsigned long long) ino,
1108 (unsigned long long) myino,
1109 (unsigned int) dev,
1110 (unsigned int) mydev);
1111 /* slow validation, need to hash full file (again) */
1112 GNUNET_CONTAINER_DLL_insert (lc->isc_head,
1113 lc->isc_tail,
1114 isc);
1115 isc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
1116 isc->filename,
1117 HASHING_BLOCKSIZE,
1118 &hash_for_index_val,
1119 isc);
1120 if (NULL == isc->fhc)
1121 hash_for_index_val (isc,
1122 NULL);
1123}
1124
1125
1126/**
1127 * Handle INDEX_LIST_GET-message.
1128 *
1129 * @param cls closure
1130 * @param message the actual message
1131 */
1132static void
1133handle_client_index_list_get (void *cls,
1134 const struct GNUNET_MessageHeader *message)
1135{
1136 struct GSF_LocalClient *lc = cls;
1137
1138 GNUNET_FS_indexing_send_list (lc->mq);
1139 GNUNET_SERVICE_client_continue (lc->client);
1140}
1141
1142
1143/**
1144 * Handle UNINDEX-message.
1145 *
1146 * @param cls identification of the client
1147 * @param message the actual message
1148 */
1149static void
1150handle_client_unindex (void *cls,
1151 const struct UnindexMessage *um)
1152{
1153 struct GSF_LocalClient *lc = cls;
1154 struct GNUNET_MQ_Envelope *env;
1155 struct GNUNET_MessageHeader *msg;
1156 int found;
1157
1158 GNUNET_break (0 == um->reserved);
1159 found = GNUNET_FS_indexing_do_unindex (&um->file_id);
1160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1161 "Client requested unindexing of file `%s': %s\n",
1162 GNUNET_h2s (&um->file_id),
1163 found ? "found" : "not found");
1164 env = GNUNET_MQ_msg (msg,
1165 GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK);
1166 GNUNET_MQ_send (lc->mq,
1167 env);
1168 GNUNET_SERVICE_client_continue (lc->client);
535} 1169}
536 1170
537 1171
@@ -560,7 +1194,8 @@ shutdown_task (void *cls)
560 GSF_pending_request_done_ (); 1194 GSF_pending_request_done_ ();
561 GSF_plan_done (); 1195 GSF_plan_done ();
562 GSF_connected_peer_done_ (); 1196 GSF_connected_peer_done_ ();
563 GNUNET_DATASTORE_disconnect (GSF_dsh, GNUNET_NO); 1197 GNUNET_DATASTORE_disconnect (GSF_dsh,
1198 GNUNET_NO);
564 GSF_dsh = NULL; 1199 GSF_dsh = NULL;
565 GNUNET_DHT_disconnect (GSF_dht); 1200 GNUNET_DHT_disconnect (GSF_dht);
566 GSF_dht = NULL; 1201 GSF_dht = NULL;
@@ -610,12 +1245,10 @@ peer_init_handler (void *cls,
610/** 1245/**
611 * Process fs requests. 1246 * Process fs requests.
612 * 1247 *
613 * @param server the initialized server
614 * @param c configuration to use 1248 * @param c configuration to use
615 */ 1249 */
616static int 1250static int
617main_init (struct GNUNET_SERVER_Handle *server, 1251main_init (const struct GNUNET_CONFIGURATION_Handle *c)
618 const struct GNUNET_CONFIGURATION_Handle *c)
619{ 1252{
620 struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = { 1253 struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = {
621 GNUNET_MQ_handler_end () 1254 GNUNET_MQ_handler_end ()
@@ -635,22 +1268,6 @@ main_init (struct GNUNET_SERVER_Handle *server,
635 NULL), 1268 NULL),
636 GNUNET_MQ_handler_end () 1269 GNUNET_MQ_handler_end ()
637 }; 1270 };
638 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
639 { &GNUNET_FS_handle_index_start, NULL,
640 GNUNET_MESSAGE_TYPE_FS_INDEX_START, 0 },
641 { &GNUNET_FS_handle_index_list_get, NULL,
642 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
643 sizeof (struct GNUNET_MessageHeader) },
644 { &GNUNET_FS_handle_unindex, NULL,
645 GNUNET_MESSAGE_TYPE_FS_UNINDEX,
646 sizeof (struct UnindexMessage) },
647 { &handle_start_search, NULL,
648 GNUNET_MESSAGE_TYPE_FS_START_SEARCH, 0 },
649 { &handle_loc_sign, NULL,
650 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
651 sizeof (struct RequestLocSignatureMessage) },
652 {NULL, NULL, 0, 0}
653 };
654 int anon_p2p_off; 1271 int anon_p2p_off;
655 char *keyfile; 1272 char *keyfile;
656 1273
@@ -697,10 +1314,6 @@ main_init (struct GNUNET_SERVER_Handle *server,
697 "core"); 1314 "core");
698 return GNUNET_SYSERR; 1315 return GNUNET_SYSERR;
699 } 1316 }
700 GNUNET_SERVER_disconnect_notify (server,
701 &GSF_client_disconnect_handler_,
702 NULL);
703 GNUNET_SERVER_add_handlers (server, handlers);
704 cover_age_task = 1317 cover_age_task =
705 GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, 1318 GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
706 &age_cover_counters, 1319 &age_cover_counters,
@@ -718,22 +1331,26 @@ main_init (struct GNUNET_SERVER_Handle *server,
718 * Process fs requests. 1331 * Process fs requests.
719 * 1332 *
720 * @param cls closure 1333 * @param cls closure
721 * @param server the initialized server
722 * @param cfg configuration to use 1334 * @param cfg configuration to use
1335 * @param service the initialized service
723 */ 1336 */
724static void 1337static void
725run (void *cls, struct GNUNET_SERVER_Handle *server, 1338run (void *cls,
726 const struct GNUNET_CONFIGURATION_Handle *cfg) 1339 const struct GNUNET_CONFIGURATION_Handle *cfg,
1340 struct GNUNET_SERVICE_Handle *service)
727{ 1341{
728 unsigned long long dqs; 1342 unsigned long long dqs;
729 1343
730 GSF_cfg = cfg; 1344 GSF_cfg = cfg;
731 if (GNUNET_OK != 1345 if (GNUNET_OK !=
732 GNUNET_CONFIGURATION_get_value_size (GSF_cfg, "fs", "DATASTORE_QUEUE_SIZE", 1346 GNUNET_CONFIGURATION_get_value_size (GSF_cfg,
1347 "fs",
1348 "DATASTORE_QUEUE_SIZE",
733 &dqs)) 1349 &dqs))
734 { 1350 {
735 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO, 1351 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
736 "fs", "DATASTORE_QUEUE_SIZE"); 1352 "fs",
1353 "DATASTORE_QUEUE_SIZE");
737 dqs = 1024; 1354 dqs = 1024;
738 } 1355 }
739 GSF_datastore_queue_size = (unsigned int) dqs; 1356 GSF_datastore_queue_size = (unsigned int) dqs;
@@ -754,11 +1371,14 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
754 GSF_plan_init (); 1371 GSF_plan_init ();
755 GSF_pending_request_init_ (); 1372 GSF_pending_request_init_ ();
756 GSF_connected_peer_init_ (); 1373 GSF_connected_peer_init_ ();
757 GSF_ats = GNUNET_ATS_performance_init (GSF_cfg, &update_latencies, NULL); 1374 GSF_ats = GNUNET_ATS_performance_init (GSF_cfg,
1375 &update_latencies,
1376 NULL);
758 GSF_push_init_ (); 1377 GSF_push_init_ ();
759 GSF_put_init_ (); 1378 GSF_put_init_ ();
760 if ((GNUNET_OK != GNUNET_FS_indexing_init (cfg, GSF_dsh)) || 1379 if ( (GNUNET_OK != GNUNET_FS_indexing_init (cfg,
761 (GNUNET_OK != main_init (server, cfg))) 1380 GSF_dsh)) ||
1381 (GNUNET_OK != main_init (cfg)) )
762 { 1382 {
763 GNUNET_SCHEDULER_shutdown (); 1383 GNUNET_SCHEDULER_shutdown ();
764 shutdown_task (NULL); 1384 shutdown_task (NULL);
@@ -768,18 +1388,36 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
768 1388
769 1389
770/** 1390/**
771 * The main function for the fs service. 1391 * Define "main" method using service macro.
772 *
773 * @param argc number of arguments from the command line
774 * @param argv command line arguments
775 * @return 0 ok, 1 on error
776 */ 1392 */
777int 1393GNUNET_SERVICE_MAIN
778main (int argc, char *const *argv) 1394("fs",
779{ 1395 GNUNET_SERVICE_OPTION_NONE,
780 return (GNUNET_OK == 1396 &run,
781 GNUNET_SERVICE_run (argc, argv, "fs", GNUNET_SERVICE_OPTION_NONE, 1397 &client_connect_cb,
782 &run, NULL)) ? 0 : 1; 1398 &client_disconnect_cb,
783} 1399 NULL,
1400 GNUNET_MQ_hd_var_size (client_index_start,
1401 GNUNET_MESSAGE_TYPE_FS_INDEX_START,
1402 struct IndexStartMessage,
1403 NULL),
1404 GNUNET_MQ_hd_fixed_size (client_index_list_get,
1405 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
1406 struct GNUNET_MessageHeader,
1407 NULL),
1408 GNUNET_MQ_hd_fixed_size (client_unindex,
1409 GNUNET_MESSAGE_TYPE_FS_UNINDEX,
1410 struct UnindexMessage,
1411 NULL),
1412 GNUNET_MQ_hd_var_size (client_start_search,
1413 GNUNET_MESSAGE_TYPE_FS_START_SEARCH,
1414 struct SearchMessage,
1415 NULL),
1416 GNUNET_MQ_hd_fixed_size (client_loc_sign,
1417 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
1418 struct RequestLocSignatureMessage,
1419 NULL),
1420 GNUNET_MQ_handler_end ());
1421
784 1422
785/* end of gnunet-service-fs.c */ 1423/* 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
307GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start); 307GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start);
308 308
309 309
310
311#endif 310#endif
312/* end of gnunet-service-fs.h */ 311/* 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
79 79
80/** 80/**
81 * Head of linked list of indexed files. 81 * Head of linked list of indexed files.
82 * FIXME: we don't need both a DLL and a hashmap here!
82 */ 83 */
83static struct IndexInfo *indexed_files_head; 84static struct IndexInfo *indexed_files_head;
84 85
@@ -117,29 +118,38 @@ write_index_list ()
117 struct IndexInfo *pos; 118 struct IndexInfo *pos;
118 119
119 if (GNUNET_OK != 120 if (GNUNET_OK !=
120 GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) 121 GNUNET_CONFIGURATION_get_value_filename (cfg, "FS",
122 "INDEXDB",
123 &fn))
121 { 124 {
122 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 125 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
123 "fs", "INDEXDB"); 126 "fs",
127 "INDEXDB");
124 return; 128 return;
125 } 129 }
126 wh = GNUNET_BIO_write_open (fn); 130 wh = GNUNET_BIO_write_open (fn);
127 if (NULL == wh) 131 if (NULL == wh)
128 { 132 {
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
130 _("Could not open `%s'.\n"), fn); 134 _("Could not open `%s'.\n"),
135 fn);
131 GNUNET_free (fn); 136 GNUNET_free (fn);
132 return; 137 return;
133 } 138 }
134 for (pos = indexed_files_head; NULL != pos; pos = pos->next) 139 for (pos = indexed_files_head; NULL != pos; pos = pos->next)
135 if ((GNUNET_OK != 140 if ((GNUNET_OK !=
136 GNUNET_BIO_write (wh, &pos->file_id, sizeof (struct GNUNET_HashCode))) || 141 GNUNET_BIO_write (wh,
137 (GNUNET_OK != GNUNET_BIO_write_string (wh, pos->filename))) 142 &pos->file_id,
143 sizeof (struct GNUNET_HashCode))) ||
144 (GNUNET_OK !=
145 GNUNET_BIO_write_string (wh,
146 pos->filename)))
138 break; 147 break;
139 if (GNUNET_OK != GNUNET_BIO_write_close (wh)) 148 if (GNUNET_OK != GNUNET_BIO_write_close (wh))
140 { 149 {
141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
142 _("Error writing `%s'.\n"), fn); 151 _("Error writing `%s'.\n"),
152 fn);
143 GNUNET_free (fn); 153 GNUNET_free (fn);
144 return; 154 return;
145 } 155 }
@@ -162,10 +172,14 @@ read_index_list ()
162 char *emsg; 172 char *emsg;
163 173
164 if (GNUNET_OK != 174 if (GNUNET_OK !=
165 GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) 175 GNUNET_CONFIGURATION_get_value_filename (cfg,
176 "FS",
177 "INDEXDB",
178 &fn))
166 { 179 {
167 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 180 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
168 "fs", "INDEXDB"); 181 "fs",
182 "INDEXDB");
169 return; 183 return;
170 } 184 }
171 if (GNUNET_NO == GNUNET_DISK_file_test (fn)) 185 if (GNUNET_NO == GNUNET_DISK_file_test (fn))
@@ -178,16 +192,22 @@ read_index_list ()
178 if (NULL == rh) 192 if (NULL == rh)
179 { 193 {
180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
181 _("Could not open `%s'.\n"), fn); 195 _("Could not open `%s'.\n"),
196 fn);
182 GNUNET_free (fn); 197 GNUNET_free (fn);
183 return; 198 return;
184 } 199 }
185 while ((GNUNET_OK == 200 while ( (GNUNET_OK ==
186 GNUNET_BIO_read (rh, "Hash of indexed file", &hc, 201 GNUNET_BIO_read (rh,
187 sizeof (struct GNUNET_HashCode))) && 202 "Hash of indexed file",
188 (GNUNET_OK == 203 &hc,
189 GNUNET_BIO_read_string (rh, "Name of indexed file", &fname, 204 sizeof (struct GNUNET_HashCode))) &&
190 1024 * 16)) && (fname != NULL)) 205 (GNUNET_OK ==
206 GNUNET_BIO_read_string (rh,
207 "Name of indexed file",
208 &fname,
209 1024 * 16)) &&
210 (fname != NULL) )
191 { 211 {
192 slen = strlen (fname) + 1; 212 slen = strlen (fname) + 1;
193 pos = GNUNET_malloc (sizeof (struct IndexInfo) + slen); 213 pos = GNUNET_malloc (sizeof (struct IndexInfo) + slen);
@@ -215,250 +235,6 @@ read_index_list ()
215 235
216 236
217/** 237/**
218 * We've validated the hash of the file we're about to index. Signal
219 * success to the client and update our internal data structures.
220 *
221 * @param ii the index info entry for the request
222 */
223static void
224signal_index_ok (struct IndexInfo *ii)
225{
226 struct IndexInfo *ir;
227 if (GNUNET_SYSERR ==
228 GNUNET_CONTAINER_multihashmap_put (ifm, &ii->file_id,
229 ii,
230 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
231 {
232 ir = GNUNET_CONTAINER_multihashmap_get (ifm,
233 &ii->file_id);
234 GNUNET_assert (NULL != ir);
235 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236 _
237 ("Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"),
238 ii->filename,
239 ir->filename);
240 GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
241 GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
242 GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
243 GNUNET_free (ii);
244 return;
245 }
246 GNUNET_CONTAINER_DLL_insert (indexed_files_head,
247 indexed_files_tail,
248 ii);
249 write_index_list ();
250 GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
251 GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
252 GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
253 ii->tc = NULL;
254}
255
256
257/**
258 * Function called once the hash computation over an
259 * indexed file has completed.
260 *
261 * @param cls closure, our publishing context
262 * @param res resulting hash, NULL on error
263 */
264static void
265hash_for_index_val (void *cls, const struct GNUNET_HashCode * res)
266{
267 struct IndexInfo *ii = cls;
268
269 ii->fhc = NULL;
270 if ((res == NULL) ||
271 (0 != memcmp (res, &ii->file_id, sizeof (struct GNUNET_HashCode))))
272 {
273 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
274 _
275 ("Hash mismatch trying to index file `%s' which has hash `%s'\n"),
276 ii->filename, GNUNET_h2s (res));
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wanted `%s'\n",
278 GNUNET_h2s (&ii->file_id));
279 GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
280 GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED);
281 GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
282 GNUNET_free (ii);
283 return;
284 }
285 signal_index_ok (ii);
286}
287
288
289/**
290 * Handle INDEX_START-message.
291 *
292 * @param cls closure
293 * @param client identification of the client
294 * @param message the actual message
295 */
296void
297GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client,
298 const struct GNUNET_MessageHeader *message)
299{
300 const struct IndexStartMessage *ism;
301 char *fn;
302 uint16_t msize;
303 struct IndexInfo *ii;
304 size_t slen;
305 uint64_t dev;
306 uint64_t ino;
307 uint64_t mydev;
308 uint64_t myino;
309
310 msize = ntohs (message->size);
311 if ((msize <= sizeof (struct IndexStartMessage)) ||
312 (((const char *) message)[msize - 1] != '\0'))
313 {
314 GNUNET_break (0);
315 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
316 return;
317 }
318 ism = (const struct IndexStartMessage *) message;
319 if (0 != ism->reserved)
320 {
321 GNUNET_break (0);
322 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
323 return;
324 }
325 fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
326 if (fn == NULL)
327 {
328 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
329 return;
330 }
331 dev = GNUNET_ntohll (ism->device);
332 ino = GNUNET_ntohll (ism->inode);
333 ism = (const struct IndexStartMessage *) message;
334 slen = strlen (fn) + 1;
335 ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen);
336 ii->filename = (const char *) &ii[1];
337 GNUNET_memcpy (&ii[1], fn, slen);
338 ii->file_id = ism->file_id;
339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for file `%s'\n",
340 "START_INDEX", ii->filename);
341 ii->tc = GNUNET_SERVER_transmit_context_create (client);
342 mydev = 0;
343 myino = 0;
344 if (((dev != 0) || (ino != 0)) &&
345 (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, &mydev, &myino)) &&
346 ((dev == mydev) && (ino == myino)))
347 {
348 /* fast validation OK! */
349 signal_index_ok (ii);
350 GNUNET_free (fn);
351 return;
352 }
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354 "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n",
355 (unsigned long long) ino, (unsigned long long) myino,
356 (unsigned int) dev, (unsigned int) mydev);
357 /* slow validation, need to hash full file (again) */
358 ii->fhc =
359 GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, fn,
360 HASHING_BLOCKSIZE, &hash_for_index_val, ii);
361 if (ii->fhc == NULL)
362 hash_for_index_val (ii, NULL);
363 GNUNET_free (fn);
364}
365
366
367/**
368 * Handle INDEX_LIST_GET-message.
369 *
370 * @param cls closure
371 * @param client identification of the client
372 * @param message the actual message
373 */
374void
375GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client,
376 const struct GNUNET_MessageHeader *message)
377{
378 struct GNUNET_SERVER_TransmitContext *tc;
379 struct IndexInfoMessage *iim;
380 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
381 size_t slen;
382 const char *fn;
383 struct IndexInfo *pos;
384
385 tc = GNUNET_SERVER_transmit_context_create (client);
386 iim = (struct IndexInfoMessage *) buf;
387 for (pos = indexed_files_head; NULL != pos; pos = pos->next)
388 {
389 fn = pos->filename;
390 slen = strlen (fn) + 1;
391 if (slen + sizeof (struct IndexInfoMessage) >=
392 GNUNET_SERVER_MAX_MESSAGE_SIZE)
393 {
394 GNUNET_break (0);
395 break;
396 }
397 iim->header.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY);
398 iim->header.size = htons (slen + sizeof (struct IndexInfoMessage));
399 iim->reserved = 0;
400 iim->file_id = pos->file_id;
401 GNUNET_memcpy (&iim[1], fn, slen);
402 GNUNET_SERVER_transmit_context_append_message (tc, &iim->header);
403 }
404 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
405 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END);
406 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES);
407}
408
409
410/**
411 * Handle UNINDEX-message.
412 *
413 * @param cls closure
414 * @param client identification of the client
415 * @param message the actual message
416 */
417void
418GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client,
419 const struct GNUNET_MessageHeader *message)
420{
421 const struct UnindexMessage *um;
422 struct IndexInfo *pos;
423 struct GNUNET_SERVER_TransmitContext *tc;
424 int found;
425
426 um = (const struct UnindexMessage *) message;
427 if (0 != um->reserved)
428 {
429 GNUNET_break (0);
430 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
431 return;
432 }
433 found = GNUNET_NO;
434 for (pos = indexed_files_head; NULL != pos; pos = pos->next)
435 {
436 if (0 == memcmp (&pos->file_id, &um->file_id, sizeof (struct GNUNET_HashCode)))
437 {
438 GNUNET_CONTAINER_DLL_remove (indexed_files_head,
439 indexed_files_tail,
440 pos);
441 GNUNET_break (GNUNET_OK ==
442 GNUNET_CONTAINER_multihashmap_remove (ifm, &pos->file_id,
443 pos));
444 GNUNET_free (pos);
445 found = GNUNET_YES;
446 break;
447 }
448 }
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Client requested unindexing of file `%s': %s\n",
451 GNUNET_h2s (&um->file_id), found ? "found" : "not found");
452 if (GNUNET_YES == found)
453 write_index_list ();
454 tc = GNUNET_SERVER_transmit_context_create (client);
455 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
456 GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK);
457 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES);
458}
459
460
461/**
462 * Continuation called from datastore's remove 238 * Continuation called from datastore's remove
463 * function. 239 * function.
464 * 240 *
@@ -498,9 +274,12 @@ remove_cont (void *cls, int success,
498 * @return GNUNET_OK on success 274 * @return GNUNET_OK on success
499 */ 275 */
500int 276int
501GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size, 277GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key,
502 const void *data, enum GNUNET_BLOCK_Type type, 278 uint32_t size,
503 uint32_t priority, uint32_t anonymity, 279 const void *data,
280 enum GNUNET_BLOCK_Type type,
281 uint32_t priority,
282 uint32_t anonymity,
504 struct GNUNET_TIME_Absolute expiration, 283 struct GNUNET_TIME_Absolute expiration,
505 uint64_t uid, 284 uint64_t uid,
506 GNUNET_DATASTORE_DatumProcessor cont, 285 GNUNET_DATASTORE_DatumProcessor cont,
@@ -522,70 +301,246 @@ GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t s
522 if (size != sizeof (struct OnDemandBlock)) 301 if (size != sizeof (struct OnDemandBlock))
523 { 302 {
524 GNUNET_break (0); 303 GNUNET_break (0);
525 GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, 304 GNUNET_DATASTORE_remove (dsh,
305 key,
306 size,
307 data,
308 -1,
309 -1,
526 &remove_cont, NULL); 310 &remove_cont, NULL);
527 return GNUNET_SYSERR; 311 return GNUNET_SYSERR;
528 } 312 }
529 odb = (const struct OnDemandBlock *) data; 313 odb = (const struct OnDemandBlock *) data;
530 off = GNUNET_ntohll (odb->offset); 314 off = GNUNET_ntohll (odb->offset);
531 ii = GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id); 315 ii = GNUNET_CONTAINER_multihashmap_get (ifm,
316 &odb->file_id);
532 if (NULL == ii) 317 if (NULL == ii)
533 { 318 {
534 GNUNET_break (0); 319 GNUNET_break (0);
320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
321 "Failed to find index %s\n",
322 GNUNET_h2s (&odb->file_id));
535 return GNUNET_SYSERR; 323 return GNUNET_SYSERR;
536 } 324 }
537 fn = ii->filename; 325 fn = ii->filename;
538 if ((NULL == fn) || (0 != ACCESS (fn, R_OK))) 326 if ((NULL == fn) || (0 != ACCESS (fn, R_OK)))
539 { 327 {
540 GNUNET_STATISTICS_update (GSF_stats, 328 GNUNET_STATISTICS_update (GSF_stats,
541 gettext_noop 329 gettext_noop ("# index blocks removed: original file inaccessible"),
542 ("# index blocks removed: original file inaccessible"), 330 1,
543 1, GNUNET_YES); 331 GNUNET_YES);
544 GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, 332 GNUNET_DATASTORE_remove (dsh,
545 &remove_cont, NULL); 333 key,
334 size,
335 data,
336 -1,
337 -1,
338 &remove_cont,
339 NULL);
546 return GNUNET_SYSERR; 340 return GNUNET_SYSERR;
547 } 341 }
548 if ((NULL == 342 if ( (NULL ==
549 (fh = 343 (fh =
550 GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, 344 GNUNET_DISK_file_open (fn,
551 GNUNET_DISK_PERM_NONE))) || 345 GNUNET_DISK_OPEN_READ,
552 (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) || 346 GNUNET_DISK_PERM_NONE))) ||
553 (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof (ndata))))) 347 (off != GNUNET_DISK_file_seek (fh,
348 off,
349 GNUNET_DISK_SEEK_SET)) ||
350 (-1 == (nsize = GNUNET_DISK_file_read (fh,
351 ndata,
352 sizeof (ndata)))) )
554 { 353 {
555 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 354 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
556 _ 355 _("Could not access indexed file `%s' (%s) at offset %llu: %s\n"),
557 ("Could not access indexed file `%s' (%s) at offset %llu: %s\n"), 356 GNUNET_h2s (&odb->file_id),
558 GNUNET_h2s (&odb->file_id), fn, (unsigned long long) off, 357 fn,
358 (unsigned long long) off,
559 (fn == NULL) ? _("not indexed") : STRERROR (errno)); 359 (fn == NULL) ? _("not indexed") : STRERROR (errno));
560 if (fh != NULL) 360 if (fh != NULL)
561 GNUNET_DISK_file_close (fh); 361 GNUNET_DISK_file_close (fh);
562 GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, 362 GNUNET_DATASTORE_remove (dsh,
563 &remove_cont, NULL); 363 key,
364 size,
365 data,
366 -1,
367 -1,
368 &remove_cont,
369 NULL);
564 return GNUNET_SYSERR; 370 return GNUNET_SYSERR;
565 } 371 }
566 GNUNET_DISK_file_close (fh); 372 GNUNET_DISK_file_close (fh);
567 GNUNET_CRYPTO_hash (ndata, nsize, &nkey); 373 GNUNET_CRYPTO_hash (ndata,
568 GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv); 374 nsize,
569 GNUNET_CRYPTO_symmetric_encrypt (ndata, nsize, &skey, &iv, edata); 375 &nkey);
570 GNUNET_CRYPTO_hash (edata, nsize, &query); 376 GNUNET_CRYPTO_hash_to_aes_key (&nkey,
571 if (0 != memcmp (&query, key, sizeof (struct GNUNET_HashCode))) 377 &skey,
378 &iv);
379 GNUNET_CRYPTO_symmetric_encrypt (ndata,
380 nsize,
381 &skey,
382 &iv,
383 edata);
384 GNUNET_CRYPTO_hash (edata,
385 nsize,
386 &query);
387 if (0 != memcmp (&query,
388 key,
389 sizeof (struct GNUNET_HashCode)))
572 { 390 {
573 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 391 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
574 _("Indexed file `%s' changed at offset %llu\n"), fn, 392 _("Indexed file `%s' changed at offset %llu\n"),
393 fn,
575 (unsigned long long) off); 394 (unsigned long long) off);
576 GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, 395 GNUNET_DATASTORE_remove (dsh,
577 &remove_cont, NULL); 396 key,
397 size,
398 data,
399 -1,
400 -1,
401 &remove_cont,
402 NULL);
578 return GNUNET_SYSERR; 403 return GNUNET_SYSERR;
579 } 404 }
580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
581 "On-demand encoded block for query `%s'\n", GNUNET_h2s (key)); 406 "On-demand encoded block for query `%s'\n",
582 cont (cont_cls, key, nsize, edata, GNUNET_BLOCK_TYPE_FS_DBLOCK, priority, 407 GNUNET_h2s (key));
583 anonymity, expiration, uid); 408 cont (cont_cls,
409 key,
410 nsize,
411 edata,
412 GNUNET_BLOCK_TYPE_FS_DBLOCK,
413 priority,
414 anonymity,
415 expiration,
416 uid);
584 return GNUNET_OK; 417 return GNUNET_OK;
585} 418}
586 419
587 420
588/** 421/**
422 * Transmit information about indexed files to @a mq.
423 *
424 * @param mq message queue to send information to
425 */
426void
427GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq)
428{
429 struct GNUNET_MQ_Envelope *env;
430 struct IndexInfoMessage *iim;
431 struct GNUNET_MessageHeader *iem;
432 size_t slen;
433 const char *fn;
434 struct IndexInfo *pos;
435
436 for (pos = indexed_files_head; NULL != pos; pos = pos->next)
437 {
438 fn = pos->filename;
439 slen = strlen (fn) + 1;
440 if (slen + sizeof (struct IndexInfoMessage) >=
441 GNUNET_SERVER_MAX_MESSAGE_SIZE)
442 {
443 GNUNET_break (0);
444 break;
445 }
446 env = GNUNET_MQ_msg_extra (iim,
447 slen,
448 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY);
449 iim->reserved = 0;
450 iim->file_id = pos->file_id;
451 GNUNET_memcpy (&iim[1],
452 fn,
453 slen);
454 GNUNET_MQ_send (mq,
455 env);
456 }
457 env = GNUNET_MQ_msg (iem,
458 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END);
459 GNUNET_MQ_send (mq,
460 env);
461}
462
463
464/**
465 * Remove a file from the index.
466 *
467 * @param fid identifier of the file to remove
468 * @return #GNUNET_YES if the @a fid was found
469 */
470int
471GNUNET_FS_indexing_do_unindex (const struct GNUNET_HashCode *fid)
472{
473 struct IndexInfo *pos;
474
475 for (pos = indexed_files_head; NULL != pos; pos = pos->next)
476 {
477 if (0 == memcmp (&pos->file_id,
478 fid,
479 sizeof (struct GNUNET_HashCode)))
480 {
481 GNUNET_CONTAINER_DLL_remove (indexed_files_head,
482 indexed_files_tail,
483 pos);
484 GNUNET_break (GNUNET_OK ==
485 GNUNET_CONTAINER_multihashmap_remove (ifm,
486 &pos->file_id,
487 pos));
488 GNUNET_free (pos);
489 write_index_list ();
490 return GNUNET_YES;
491 }
492 }
493 return GNUNET_NO;
494}
495
496
497/**
498 * Add the given file to the list of indexed files.
499 *
500 * @param filename name of the file
501 * @param file_id hash identifier for @a filename
502 */
503void
504GNUNET_FS_add_to_index (const char *filename,
505 const struct GNUNET_HashCode *file_id)
506{
507 struct IndexInfo *ii;
508 size_t slen;
509
510 ii = GNUNET_CONTAINER_multihashmap_get (ifm,
511 file_id);
512 if (NULL != ii)
513 {
514 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
515 _("Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"),
516 filename,
517 ii->filename);
518 return;
519 }
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521 "Adding file %s to index as %s\n",
522 filename,
523 GNUNET_h2s (file_id));
524 slen = strlen (filename) + 1;
525 ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen);
526 ii->file_id = *file_id;
527 ii->filename = (const char *) &ii[1];
528 memcpy (&ii[1],
529 filename,
530 slen);
531 GNUNET_CONTAINER_DLL_insert (indexed_files_head,
532 indexed_files_tail,
533 ii);
534 GNUNET_assert (GNUNET_OK ==
535 GNUNET_CONTAINER_multihashmap_put (ifm,
536 &ii->file_id,
537 ii,
538 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
539 write_index_list ();
540}
541
542
543/**
589 * Shutdown the module. 544 * Shutdown the module.
590 */ 545 */
591void 546void
@@ -602,7 +557,8 @@ GNUNET_FS_indexing_done ()
602 GNUNET_CRYPTO_hash_file_cancel (pos->fhc); 557 GNUNET_CRYPTO_hash_file_cancel (pos->fhc);
603 GNUNET_break (GNUNET_OK == 558 GNUNET_break (GNUNET_OK ==
604 GNUNET_CONTAINER_multihashmap_remove (ifm, 559 GNUNET_CONTAINER_multihashmap_remove (ifm,
605 &pos->file_id, pos)); 560 &pos->file_id,
561 pos));
606 GNUNET_free (pos); 562 GNUNET_free (pos);
607 } 563 }
608 GNUNET_CONTAINER_multihashmap_destroy (ifm); 564 GNUNET_CONTAINER_multihashmap_destroy (ifm);
@@ -623,7 +579,8 @@ GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c,
623{ 579{
624 cfg = c; 580 cfg = c;
625 dsh = d; 581 dsh = d;
626 ifm = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_YES); 582 ifm = GNUNET_CONTAINER_multihashmap_create (128,
583 GNUNET_YES);
627 read_index_list (); 584 read_index_list ();
628 return GNUNET_OK; 585 return GNUNET_OK;
629} 586}
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 @@
51 * @param uid unique identifier for the datum; 51 * @param uid unique identifier for the datum;
52 * maybe 0 if no unique identifier is available 52 * maybe 0 if no unique identifier is available
53 * @param cont function to call with the actual block (at most once, on success) 53 * @param cont function to call with the actual block (at most once, on success)
54 * @param cont_cls closure for cont 54 * @param cont_cls closure for @a cont
55 * @return GNUNET_OK on success 55 * @return #GNUNET_OK on success
56 */ 56 */
57int 57int
58GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size, 58GNUNET_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
63 GNUNET_DATASTORE_DatumProcessor cont, 63 GNUNET_DATASTORE_DatumProcessor cont,
64 void *cont_cls); 64 void *cont_cls);
65 65
66
66/** 67/**
67 * Handle INDEX_START-message. 68 * Transmit information about indexed files to @a mq.
68 * 69 *
69 * @param cls closure 70 * @param mq message queue to send information to
70 * @param client identification of the client
71 * @param message the actual message
72 */ 71 */
73void 72void
74GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client, 73GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq);
75 const struct GNUNET_MessageHeader *message);
76 74
77 75
78/** 76/**
79 * Handle INDEX_LIST_GET-message. 77 * Remove a file from the index.
80 * 78 *
81 * @param cls closure 79 * @param fid identifier of the file to remove
82 * @param client identification of the client 80 * @return #GNUNET_YES if the @a fid was found
83 * @param message the actual message
84 */ 81 */
85void 82int
86GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client, 83GNUNET_FS_indexing_do_unindex (const struct GNUNET_HashCode *fid);
87 const struct GNUNET_MessageHeader *message);
88 84
89 85
90/** 86/**
91 * Handle UNINDEX-message. 87 * Add the given file to the list of indexed files.
92 * 88 *
93 * @param cls closure 89 * @param filename name of the file
94 * @param client identification of the client 90 * @param file_id hash identifier for @a filename
95 * @param message the actual message
96 */ 91 */
97void 92void
98GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client, 93GNUNET_FS_add_to_index (const char *filename,
99 const struct GNUNET_MessageHeader *message); 94 const struct GNUNET_HashCode *file_id);
100 95
101 96
102/** 97/**
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 @@
29#include "gnunet-service-fs_pr.h" 29#include "gnunet-service-fs_pr.h"
30 30
31 31
32/**
33 * Doubly-linked list of requests we are performing
34 * on behalf of the same client.
35 */
36struct ClientRequest
37{
38
39 /**
40 * This is a doubly-linked list.
41 */
42 struct ClientRequest *next;
43
44 /**
45 * This is a doubly-linked list.
46 */
47 struct ClientRequest *prev;
48
49 /**
50 * Request this entry represents.
51 */
52 struct GSF_PendingRequest *pr;
53
54 /**
55 * Client list this request belongs to.
56 */
57 struct GSF_LocalClient *lc;
58
59 /**
60 * Task scheduled to destroy the request.
61 */
62 struct GNUNET_SCHEDULER_Task * kill_task;
63
64};
65
66
67/**
68 * Replies to be transmitted to the client. The actual
69 * response message is allocated after this struct.
70 */
71struct ClientResponse
72{
73 /**
74 * This is a doubly-linked list.
75 */
76 struct ClientResponse *next;
77
78 /**
79 * This is a doubly-linked list.
80 */
81 struct ClientResponse *prev;
82
83 /**
84 * Client list entry this response belongs to.
85 */
86 struct GSF_LocalClient *lc;
87
88 /**
89 * Number of bytes in the response.
90 */
91 size_t msize;
92};
93
94
95/**
96 * A local client.
97 */
98struct GSF_LocalClient
99{
100
101 /**
102 * We keep clients in a DLL.
103 */
104 struct GSF_LocalClient *next;
105
106 /**
107 * We keep clients in a DLL.
108 */
109 struct GSF_LocalClient *prev;
110
111 /**
112 * ID of the client.
113 */
114 struct GNUNET_SERVER_Client *client;
115
116 /**
117 * Head of list of requests performed on behalf
118 * of this client right now.
119 */
120 struct ClientRequest *cr_head;
121
122 /**
123 * Tail of list of requests performed on behalf
124 * of this client right now.
125 */
126 struct ClientRequest *cr_tail;
127
128 /**
129 * Head of linked list of responses.
130 */
131 struct ClientResponse *res_head;
132
133 /**
134 * Tail of linked list of responses.
135 */
136 struct ClientResponse *res_tail;
137
138 /**
139 * Context for sending replies.
140 */
141 struct GNUNET_SERVER_TransmitHandle *th;
142
143};
144
145
146/**
147 * Head of linked list of our local clients.
148 */
149static struct GSF_LocalClient *client_head;
150
151/**
152 * Head of linked list of our local clients.
153 */
154static struct GSF_LocalClient *client_tail;
155
156
157/**
158 * Look up a local client record or create one if it
159 * doesn't exist yet.
160 *
161 * @param client handle of the client
162 * @return handle to local client entry
163 */
164struct GSF_LocalClient *
165GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client)
166{
167 struct GSF_LocalClient *pos;
168
169 pos = client_head;
170 while ((NULL != pos) && (pos->client != client))
171 pos = pos->next;
172 if (NULL != pos)
173 return pos;
174 pos = GNUNET_new (struct GSF_LocalClient);
175 pos->client = client;
176 GNUNET_CONTAINER_DLL_insert (client_head,
177 client_tail,
178 pos);
179 return pos;
180}
181
182
183/**
184 * Free the given client request.
185 *
186 * @param cls the client request to free
187 */
188static void
189client_request_destroy (void *cls)
190{
191 struct ClientRequest *cr = cls;
192 struct GSF_LocalClient *lc;
193
194 cr->kill_task = NULL;
195 lc = cr->lc;
196 GNUNET_CONTAINER_DLL_remove (lc->cr_head,
197 lc->cr_tail,
198 cr);
199 GSF_pending_request_cancel_ (cr->pr,
200 GNUNET_YES);
201 GNUNET_STATISTICS_update (GSF_stats,
202 gettext_noop ("# client searches active"),
203 -1,
204 GNUNET_NO);
205 GNUNET_free (cr);
206}
207
208
209/**
210 * Handle a reply to a pending request. Also called if a request
211 * expires (then with data == NULL). The handler may be called
212 * many times (depending on the request type), but will not be
213 * called during or after a call to #GSF_pending_request_cancel()
214 * and will also not be called anymore after a call signalling
215 * expiration.
216 *
217 * @param cls user-specified closure
218 * @param eval evaluation of the result
219 * @param pr handle to the original pending request
220 * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
221 * @param expiration when does @a data expire?
222 * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
223 * @param type type of the block
224 * @param data response data, NULL on request expiration
225 * @param data_len number of bytes in @a data
226 */
227static void
228client_response_handler (void *cls,
229 enum GNUNET_BLOCK_EvaluationResult eval,
230 struct GSF_PendingRequest *pr,
231 uint32_t reply_anonymity_level,
232 struct GNUNET_TIME_Absolute expiration,
233 struct GNUNET_TIME_Absolute last_transmission,
234 enum GNUNET_BLOCK_Type type,
235 const void *data,
236 size_t data_len)
237{
238 struct ClientRequest *cr = cls;
239 struct GSF_LocalClient *lc;
240 struct ClientPutMessage *pm;
241 const struct GSF_PendingRequestData *prd;
242 size_t msize;
243
244 if (NULL == data)
245 {
246 /* local-only request, with no result, clean up. */
247 if (NULL == cr->kill_task)
248 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
249 cr);
250 return;
251 }
252 prd = GSF_pending_request_get_data_ (pr);
253 GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY);
254 if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
255 {
256 GNUNET_break (0);
257 return;
258 }
259 GNUNET_STATISTICS_update (GSF_stats,
260 gettext_noop
261 ("# replies received for local clients"), 1,
262 GNUNET_NO);
263 GNUNET_assert (pr == cr->pr);
264 lc = cr->lc;
265 msize = sizeof (struct ClientPutMessage) + data_len;
266 {
267 char buf[msize] GNUNET_ALIGN;
268
269 pm = (struct ClientPutMessage *) buf;
270 pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT);
271 pm->header.size = htons (msize);
272 pm->type = htonl (type);
273 pm->expiration = GNUNET_TIME_absolute_hton (expiration);
274 pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
275 pm->num_transmissions = htonl (prd->num_transmissions);
276 pm->respect_offered = htonl (prd->respect_offered);
277 GNUNET_memcpy (&pm[1], data, data_len);
278 GSF_local_client_transmit_ (lc, &pm->header);
279 }
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281 "Queued reply to query `%s' for local client\n",
282 GNUNET_h2s (&prd->query));
283 if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval)
284 {
285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286 "Evaluation %d - keeping query alive\n",
287 (int) eval);
288 return;
289 }
290 if (NULL == cr->kill_task)
291 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, cr);
292}
293
294
295/**
296 * Handle START_SEARCH-message (search request from local client).
297 * Only responsible for creating the request entry itself and setting
298 * up reply callback and cancellation on client disconnect. Does NOT
299 * execute the actual request strategy (planning).
300 *
301 * @param client identification of the client
302 * @param message the actual message
303 * @param prptr where to store the pending request handle for the request
304 * @return #GNUNET_YES to start local processing,
305 * #GNUNET_NO to not (yet) start local processing,
306 * #GNUNET_SYSERR on error
307 */
308int
309GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client,
310 const struct GNUNET_MessageHeader *message,
311 struct GSF_PendingRequest **prptr)
312{
313 static struct GNUNET_PeerIdentity all_zeros;
314 const struct SearchMessage *sm;
315 struct GSF_LocalClient *lc;
316 struct ClientRequest *cr;
317 struct GSF_PendingRequestData *prd;
318 uint16_t msize;
319 unsigned int sc;
320 enum GNUNET_BLOCK_Type type;
321 enum GSF_PendingRequestOptions options;
322
323 msize = ntohs (message->size);
324 if ((msize < sizeof (struct SearchMessage)) ||
325 (0 != (msize - sizeof (struct SearchMessage)) % sizeof (struct GNUNET_HashCode)))
326 {
327 GNUNET_break (0);
328 *prptr = NULL;
329 return GNUNET_SYSERR;
330 }
331 GNUNET_STATISTICS_update (GSF_stats,
332 gettext_noop ("# client searches received"),
333 1,
334 GNUNET_NO);
335 sc = (msize - sizeof (struct SearchMessage)) / sizeof (struct GNUNET_HashCode);
336 sm = (const struct SearchMessage *) message;
337 type = ntohl (sm->type);
338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
339 "Received request for `%s' of type %u from local client\n",
340 GNUNET_h2s (&sm->query), (unsigned int) type);
341 lc = GSF_local_client_lookup_ (client);
342 cr = NULL;
343 /* detect duplicate UBLOCK requests */
344 if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) ||
345 (type == GNUNET_BLOCK_TYPE_ANY))
346 {
347 cr = lc->cr_head;
348 while (NULL != cr)
349 {
350 prd = GSF_pending_request_get_data_ (cr->pr);
351 /* only unify with queries that hae not yet started local processing
352 (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a
353 matching query and type */
354 if ((GNUNET_YES != prd->has_started) &&
355 (0 != memcmp (&prd->query,
356 &sm->query,
357 sizeof (struct GNUNET_HashCode))) &&
358 (prd->type == type))
359 break;
360 cr = cr->next;
361 }
362 }
363 if (NULL != cr)
364 {
365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
366 "Have existing request, merging content-seen lists.\n");
367 GSF_pending_request_update_ (cr->pr,
368 (const struct GNUNET_HashCode *) &sm[1],
369 sc);
370 GNUNET_STATISTICS_update (GSF_stats,
371 gettext_noop
372 ("# client searches updated (merged content seen list)"),
373 1, GNUNET_NO);
374 }
375 else
376 {
377 GNUNET_STATISTICS_update (GSF_stats,
378 gettext_noop ("# client searches active"), 1,
379 GNUNET_NO);
380 cr = GNUNET_new (struct ClientRequest);
381 cr->lc = lc;
382 GNUNET_CONTAINER_DLL_insert (lc->cr_head,
383 lc->cr_tail,
384 cr);
385 options = GSF_PRO_LOCAL_REQUEST;
386 if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options)))
387 options |= GSF_PRO_LOCAL_ONLY;
388 cr->pr = GSF_pending_request_create_ (options, type,
389 &sm->query,
390 (0 !=
391 memcmp (&sm->target, &all_zeros,
392 sizeof (struct GNUNET_PeerIdentity)))
393 ? &sm->target : NULL, NULL, 0,
394 0 /* bf */ ,
395 ntohl (sm->anonymity_level),
396 0 /* priority */ ,
397 0 /* ttl */ ,
398 0 /* sender PID */ ,
399 0 /* origin PID */ ,
400 (const struct GNUNET_HashCode *) &sm[1], sc,
401 &client_response_handler, cr);
402 }
403 *prptr = cr->pr;
404 return (0 !=
405 (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options))) ? GNUNET_NO :
406 GNUNET_YES;
407}
408
409
410/**
411 * Transmit the given message by copying it to the target buffer
412 * "buf". "buf" will be NULL and "size" zero if the socket was closed
413 * for writing in the meantime. In that case, do nothing
414 * (the disconnect or shutdown handler will take care of the rest).
415 * If we were able to transmit messages and there are still more
416 * pending, ask core again for further calls to this function.
417 *
418 * @param cls closure, pointer to the `struct GSF_LocalClient`
419 * @param size number of bytes available in @a buf
420 * @param buf where the callee should write the message
421 * @return number of bytes written to @a buf
422 */
423static size_t
424transmit_to_client (void *cls,
425 size_t size,
426 void *buf)
427{
428 struct GSF_LocalClient *lc = cls;
429 char *cbuf = buf;
430 struct ClientResponse *res;
431 size_t msize;
432
433 lc->th = NULL;
434 if (NULL == buf)
435 return 0;
436 msize = 0;
437 while ((NULL != (res = lc->res_head)) && (res->msize <= size))
438 {
439 GNUNET_memcpy (&cbuf[msize], &res[1], res->msize);
440 msize += res->msize;
441 size -= res->msize;
442 GNUNET_CONTAINER_DLL_remove (lc->res_head, lc->res_tail, res);
443 GNUNET_free (res);
444 }
445 if (NULL != res)
446 lc->th =
447 GNUNET_SERVER_notify_transmit_ready (lc->client, res->msize,
448 GNUNET_TIME_UNIT_FOREVER_REL,
449 &transmit_to_client, lc);
450 return msize;
451}
452
453
454/**
455 * Transmit a message to the given local client as soon as possible.
456 * If the client disconnects before transmission, the message is
457 * simply discarded.
458 *
459 * @param lc recipient
460 * @param msg message to transmit to client
461 */
462void
463GSF_local_client_transmit_ (struct GSF_LocalClient *lc,
464 const struct GNUNET_MessageHeader *msg)
465{
466 struct ClientResponse *res;
467 size_t msize;
468
469 msize = ntohs (msg->size);
470 res = GNUNET_malloc (sizeof (struct ClientResponse) + msize);
471 res->lc = lc;
472 res->msize = msize;
473 GNUNET_memcpy (&res[1],
474 msg,
475 msize);
476 GNUNET_CONTAINER_DLL_insert_tail (lc->res_head,
477 lc->res_tail,
478 res);
479 if (NULL == lc->th)
480 lc->th =
481 GNUNET_SERVER_notify_transmit_ready (lc->client, msize,
482 GNUNET_TIME_UNIT_FOREVER_REL,
483 &transmit_to_client, lc);
484}
485
486
487/**
488 * A client disconnected from us. Tear down the local client
489 * record.
490 *
491 * @param cls unused
492 * @param client handle of the client
493 */
494void
495GSF_client_disconnect_handler_ (void *cls,
496 struct GNUNET_SERVER_Client *client)
497{
498 struct GSF_LocalClient *pos;
499 struct ClientRequest *cr;
500 struct ClientResponse *res;
501
502 pos = client_head;
503 while ((pos != NULL) && (pos->client != client))
504 pos = pos->next;
505 if (NULL == pos)
506 return;
507 while (NULL != (cr = pos->cr_head))
508 {
509 if (NULL != cr->kill_task)
510 GNUNET_SCHEDULER_cancel (cr->kill_task);
511 client_request_destroy (cr);
512 }
513 while (NULL != (res = pos->res_head))
514 {
515 GNUNET_CONTAINER_DLL_remove (pos->res_head, pos->res_tail, res);
516 GNUNET_free (res);
517 }
518 if (NULL != pos->th)
519 {
520 GNUNET_SERVER_notify_transmit_ready_cancel (pos->th);
521 pos->th = NULL;
522 }
523 GSF_handle_local_client_disconnect_ (pos);
524 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos);
525 GNUNET_free (pos);
526}
527
528 32
529/* end of gnunet-service-fs_lc.c */ 33/* 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 @@
29#include "gnunet-service-fs.h" 29#include "gnunet-service-fs.h"
30 30
31 31
32/**
33 * Look up a local client record or create one if it
34 * doesn't exist yet.
35 *
36 * @param client handle of the client
37 * @return handle to local client entry
38 */
39struct GSF_LocalClient *
40GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client);
41
42
43/**
44 * Handle START_SEARCH-message (search request from local client).
45 * Only responsible for creating the request entry itself and setting
46 * up reply callback and cancellation on client disconnect. Does NOT
47 * execute the actual request strategy (planning).
48 *
49 * @param client identification of the client
50 * @param message the actual message
51 * @param prptr where to store the pending request handle for the request
52 * @return GNUNET_YES to start local processing,
53 * GNUNET_NO to not (yet) start local processing,
54 * GNUNET_SYSERR on error
55 */
56int
57GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client,
58 const struct GNUNET_MessageHeader
59 *message,
60 struct GSF_PendingRequest **prptr);
61
62
63/**
64 * Transmit a message to the given local client as soon as possible.
65 * If the client disconnects before transmission, the message is
66 * simply discarded.
67 *
68 * @param lc recipient
69 * @param msg message to transmit to client
70 */
71void
72GSF_local_client_transmit_ (struct GSF_LocalClient *lc,
73 const struct GNUNET_MessageHeader *msg);
74
75
76/**
77 * A client disconnected from us. Tear down the local client record.
78 *
79 * @param cls unused
80 * @param client handle of the client
81 */
82void
83GSF_client_disconnect_handler_ (void *cls, struct GNUNET_SERVER_Client *client);
84
85
86#endif 32#endif
87/* end of gnunet-service-fs_lc.h */ 33/* end of gnunet-service-fs_lc.h */