diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-10-01 12:53:07 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-10-01 12:53:07 +0000 |
commit | f7fac7f6736df4e350a8b5ed7d9f51782d7e039e (patch) | |
tree | 6eee38f2dbc4de932c22d213dde60cf06992b127 /src/fs/gnunet-service-fs.c | |
parent | 760f75d2d87f01ca93ebfb349eedbb4224c03c7c (diff) | |
download | gnunet-f7fac7f6736df4e350a8b5ed7d9f51782d7e039e.tar.gz gnunet-f7fac7f6736df4e350a8b5ed7d9f51782d7e039e.zip |
migrating fs to new service API
Diffstat (limited to 'src/fs/gnunet-service-fs.c')
-rw-r--r-- | src/fs/gnunet-service-fs.c | 850 |
1 files changed, 744 insertions, 106 deletions
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 | */ | ||
76 | struct 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 | */ | ||
111 | struct 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 | */ | ||
139 | struct 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 | */ | ||
178 | struct 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 | */ |
153 | int GSF_enable_randomized_delays; | 308 | int GSF_enable_randomized_delays; |
154 | 309 | ||
310 | /** | ||
311 | * Identity of this peer. | ||
312 | */ | ||
313 | struct 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 | */ |
175 | static struct GNUNET_LOAD_Value *datastore_get_load; | 335 | static 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 | */ |
180 | struct GNUNET_PeerIdentity GSF_my_id; | 346 | static void * |
347 | client_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 | */ | ||
365 | static void | ||
366 | client_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 | */ | ||
403 | static void | ||
404 | client_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 | */ | ||
478 | static void | ||
479 | client_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 | */ | ||
797 | static int | ||
798 | check_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 | */ |
463 | static void | 823 | static void |
464 | handle_start_search (void *cls, | 824 | handle_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 | */ |
504 | static void | 929 | static void |
505 | handle_loc_sign (void *cls, | 930 | handle_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 | */ | ||
967 | static int | ||
968 | check_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 | */ | ||
1002 | static void | ||
1003 | signal_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 | */ | ||
1028 | static void | ||
1029 | hash_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 | */ | ||
1068 | static void | ||
1069 | handle_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 | */ | ||
1132 | static void | ||
1133 | handle_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 | */ | ||
1149 | static void | ||
1150 | handle_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 | */ |
616 | static int | 1250 | static int |
617 | main_init (struct GNUNET_SERVER_Handle *server, | 1251 | main_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 | */ |
724 | static void | 1337 | static void |
725 | run (void *cls, struct GNUNET_SERVER_Handle *server, | 1338 | run (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 | */ |
777 | int | 1393 | GNUNET_SERVICE_MAIN |
778 | main (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 */ |