diff options
Diffstat (limited to 'src/service/namestore/gnunet-service-namestore.c')
-rw-r--r-- | src/service/namestore/gnunet-service-namestore.c | 2752 |
1 files changed, 2752 insertions, 0 deletions
diff --git a/src/service/namestore/gnunet-service-namestore.c b/src/service/namestore/gnunet-service-namestore.c new file mode 100644 index 000000000..26de295bf --- /dev/null +++ b/src/service/namestore/gnunet-service-namestore.c | |||
@@ -0,0 +1,2752 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2013, 2014, 2018 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file namestore/gnunet-service-namestore.c | ||
23 | * @brief namestore for the GNUnet naming system | ||
24 | * @author Matthias Wachs | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_gns_service.h" | ||
30 | #include "gnunet_namestore_service.h" | ||
31 | #include "gnunet_namestore_plugin.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include "gnunet_signatures.h" | ||
34 | #include "namestore.h" | ||
35 | |||
36 | #define LOG_STRERROR_FILE(kind, syscall, filename) \ | ||
37 | GNUNET_log_from_strerror_file (kind, "util", syscall, filename) | ||
38 | |||
39 | /** | ||
40 | * If a monitor takes more than 1 minute to process an event, print a warning. | ||
41 | */ | ||
42 | #define MONITOR_STALL_WARN_DELAY GNUNET_TIME_UNIT_MINUTES | ||
43 | |||
44 | /** | ||
45 | * Size of the cache used by #get_nick_record() | ||
46 | */ | ||
47 | #define NC_SIZE 16 | ||
48 | |||
49 | /** | ||
50 | * A namestore client | ||
51 | */ | ||
52 | struct NamestoreClient; | ||
53 | |||
54 | |||
55 | /** | ||
56 | * A namestore iteration operation. | ||
57 | */ | ||
58 | struct ZoneIteration | ||
59 | { | ||
60 | /** | ||
61 | * Next element in the DLL | ||
62 | */ | ||
63 | struct ZoneIteration *next; | ||
64 | |||
65 | /** | ||
66 | * Previous element in the DLL | ||
67 | */ | ||
68 | struct ZoneIteration *prev; | ||
69 | |||
70 | /** | ||
71 | * Namestore client which intiated this zone iteration | ||
72 | */ | ||
73 | struct NamestoreClient *nc; | ||
74 | |||
75 | /** | ||
76 | * The nick to add to the records | ||
77 | */ | ||
78 | struct GNUNET_GNSRECORD_Data *nick; | ||
79 | |||
80 | /** | ||
81 | * Key of the zone we are iterating over. | ||
82 | */ | ||
83 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
84 | |||
85 | /** | ||
86 | * The record set filter | ||
87 | */ | ||
88 | enum GNUNET_GNSRECORD_Filter filter; | ||
89 | |||
90 | /** | ||
91 | * Last sequence number in the zone iteration used to address next | ||
92 | * result of the zone iteration in the store | ||
93 | * | ||
94 | * Initially set to 0. | ||
95 | * Updated in #zone_iterate_proc() | ||
96 | */ | ||
97 | uint64_t seq; | ||
98 | |||
99 | /** | ||
100 | * The operation id for the zone iteration in the response for the client | ||
101 | */ | ||
102 | uint32_t request_id; | ||
103 | |||
104 | /** | ||
105 | * Offset of the zone iteration used to address next result of the zone | ||
106 | * iteration in the store | ||
107 | * | ||
108 | * Initially set to 0 in #handle_iteration_start | ||
109 | * Incremented with by every call to #handle_iteration_next | ||
110 | */ | ||
111 | uint32_t offset; | ||
112 | |||
113 | /** | ||
114 | * Number of pending cache operations triggered by this zone iteration which we | ||
115 | * need to wait for before allowing the client to continue. | ||
116 | */ | ||
117 | unsigned int cache_ops; | ||
118 | |||
119 | /** | ||
120 | * Set to #GNUNET_YES if the last iteration exhausted the limit set by the | ||
121 | * client and we should send the #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END | ||
122 | * message and free the data structure once @e cache_ops is zero. | ||
123 | */ | ||
124 | int send_end; | ||
125 | }; | ||
126 | |||
127 | /** | ||
128 | * A namestore client | ||
129 | */ | ||
130 | struct NamestoreClient | ||
131 | { | ||
132 | /** | ||
133 | * The client | ||
134 | */ | ||
135 | struct GNUNET_SERVICE_Client *client; | ||
136 | |||
137 | /** | ||
138 | * Database handle for client | ||
139 | */ | ||
140 | struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; | ||
141 | |||
142 | /** | ||
143 | * Name of loaded plugin (neeed for cleanup) | ||
144 | */ | ||
145 | char *db_lib_name; | ||
146 | |||
147 | /** | ||
148 | * GNUNET_YES if this nc has begun a transaction which is uncommited. | ||
149 | */ | ||
150 | int in_transaction; | ||
151 | |||
152 | /** | ||
153 | * Message queue for transmission to @e client | ||
154 | */ | ||
155 | struct GNUNET_MQ_Handle *mq; | ||
156 | |||
157 | /** | ||
158 | * Head of the DLL of | ||
159 | * Zone iteration operations in progress initiated by this client | ||
160 | */ | ||
161 | struct ZoneIteration *op_head; | ||
162 | |||
163 | /** | ||
164 | * Tail of the DLL of | ||
165 | * Zone iteration operations in progress initiated by this client | ||
166 | */ | ||
167 | struct ZoneIteration *op_tail; | ||
168 | }; | ||
169 | |||
170 | |||
171 | /** | ||
172 | * A namestore monitor. | ||
173 | */ | ||
174 | struct ZoneMonitor | ||
175 | { | ||
176 | /** | ||
177 | * Next element in the DLL | ||
178 | */ | ||
179 | struct ZoneMonitor *next; | ||
180 | |||
181 | /** | ||
182 | * Previous element in the DLL | ||
183 | */ | ||
184 | struct ZoneMonitor *prev; | ||
185 | |||
186 | /** | ||
187 | * Namestore client which intiated this zone monitor | ||
188 | */ | ||
189 | struct NamestoreClient *nc; | ||
190 | |||
191 | /** | ||
192 | * Private key of the zone. | ||
193 | */ | ||
194 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
195 | |||
196 | /** | ||
197 | * The record set filter | ||
198 | */ | ||
199 | enum GNUNET_GNSRECORD_Filter filter; | ||
200 | |||
201 | /** | ||
202 | * Task active during initial iteration. | ||
203 | */ | ||
204 | struct GNUNET_SCHEDULER_Task *task; | ||
205 | |||
206 | /** | ||
207 | * Task to warn about slow monitors. | ||
208 | */ | ||
209 | struct GNUNET_SCHEDULER_Task *sa_wait_warning; | ||
210 | |||
211 | /** | ||
212 | * Since when are we blocked on this monitor? | ||
213 | */ | ||
214 | struct GNUNET_TIME_Absolute sa_waiting_start; | ||
215 | |||
216 | /** | ||
217 | * Last sequence number in the zone iteration used to address next | ||
218 | * result of the zone iteration in the store | ||
219 | * | ||
220 | * Initially set to 0. | ||
221 | * Updated in #monitor_iterate_cb() | ||
222 | */ | ||
223 | uint64_t seq; | ||
224 | |||
225 | /** | ||
226 | * Current limit of how many more messages we are allowed | ||
227 | * to queue to this monitor. | ||
228 | */ | ||
229 | uint64_t limit; | ||
230 | |||
231 | /** | ||
232 | * How many more requests may we receive from the iterator | ||
233 | * before it is at the limit we gave it? Will be below or | ||
234 | * equal to @e limit. The effective limit for monitor | ||
235 | * events is thus @e iteration_cnt - @e limit! | ||
236 | */ | ||
237 | uint64_t iteration_cnt; | ||
238 | |||
239 | /** | ||
240 | * Are we (still) in the initial iteration pass? | ||
241 | */ | ||
242 | int in_first_iteration; | ||
243 | |||
244 | /** | ||
245 | * Run again because we skipped an orphan | ||
246 | */ | ||
247 | int run_again; | ||
248 | |||
249 | /** | ||
250 | * Is there a store activity waiting for this monitor? We only raise the | ||
251 | * flag when it happens and search the DLL for the store activity when we | ||
252 | * had a limit increase. If we cannot find any waiting store activity at | ||
253 | * that time, we clear the flag again. | ||
254 | */ | ||
255 | int sa_waiting; | ||
256 | }; | ||
257 | |||
258 | |||
259 | |||
260 | /** | ||
261 | * Information for an ongoing #handle_record_store() operation. | ||
262 | * Needed as we may wait for monitors to be ready for the notification. | ||
263 | */ | ||
264 | struct StoreActivity | ||
265 | { | ||
266 | /** | ||
267 | * Kept in a DLL. | ||
268 | */ | ||
269 | struct StoreActivity *next; | ||
270 | |||
271 | /** | ||
272 | * Kept in a DLL. | ||
273 | */ | ||
274 | struct StoreActivity *prev; | ||
275 | |||
276 | /** | ||
277 | * Which client triggered the store activity? | ||
278 | */ | ||
279 | struct NamestoreClient *nc; | ||
280 | |||
281 | /** | ||
282 | * The request ID | ||
283 | */ | ||
284 | uint32_t rid; | ||
285 | |||
286 | /** | ||
287 | * The currently processed record | ||
288 | */ | ||
289 | uint16_t rd_set_pos; | ||
290 | |||
291 | /** | ||
292 | * The number of records in this activity | ||
293 | */ | ||
294 | uint16_t rd_set_count; | ||
295 | |||
296 | /** | ||
297 | * Wheather or not this store action is already commited. | ||
298 | * The store activity will not be processed unless this field is GNUNET_YES | ||
299 | */ | ||
300 | int uncommited; | ||
301 | |||
302 | /** | ||
303 | * The zone private key | ||
304 | */ | ||
305 | struct GNUNET_CRYPTO_PrivateKey private_key; | ||
306 | |||
307 | /** | ||
308 | * Copy of the original record set (as data fields in @e rd will | ||
309 | * point into it!). | ||
310 | */ | ||
311 | const struct RecordSet *rs; | ||
312 | |||
313 | /** | ||
314 | * Next zone monitor that still needs to be notified about this PUT. | ||
315 | */ | ||
316 | struct ZoneMonitor *zm_pos; | ||
317 | |||
318 | }; | ||
319 | |||
320 | |||
321 | /** | ||
322 | * Entry in list of cached nick resolutions. | ||
323 | */ | ||
324 | struct NickCache | ||
325 | { | ||
326 | /** | ||
327 | * Zone the cache entry is for. | ||
328 | */ | ||
329 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
330 | |||
331 | /** | ||
332 | * Cached record data. | ||
333 | */ | ||
334 | struct GNUNET_GNSRECORD_Data *rd; | ||
335 | |||
336 | /** | ||
337 | * Timestamp when this cache entry was used last. | ||
338 | */ | ||
339 | struct GNUNET_TIME_Absolute last_used; | ||
340 | }; | ||
341 | |||
342 | /** | ||
343 | * We cache nick records to reduce DB load. | ||
344 | */ | ||
345 | static struct NickCache nick_cache[NC_SIZE]; | ||
346 | |||
347 | /** | ||
348 | * Public key of all zeros. | ||
349 | */ | ||
350 | static const struct GNUNET_CRYPTO_PrivateKey zero; | ||
351 | |||
352 | /** | ||
353 | * Configuration handle. | ||
354 | */ | ||
355 | static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg; | ||
356 | |||
357 | /** | ||
358 | * Handle to the statistics service | ||
359 | */ | ||
360 | static struct GNUNET_STATISTICS_Handle *statistics; | ||
361 | |||
362 | /** | ||
363 | * Name of the database plugin | ||
364 | */ | ||
365 | static char *db_lib_name; | ||
366 | |||
367 | /** | ||
368 | * Database handle for service | ||
369 | */ | ||
370 | struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; | ||
371 | |||
372 | |||
373 | /** | ||
374 | * First active zone monitor. | ||
375 | */ | ||
376 | static struct ZoneMonitor *monitor_head; | ||
377 | |||
378 | /** | ||
379 | * Last active zone monitor. | ||
380 | */ | ||
381 | static struct ZoneMonitor *monitor_tail; | ||
382 | |||
383 | /** | ||
384 | * Head of DLL of monitor-blocked store activities. | ||
385 | */ | ||
386 | static struct StoreActivity *sa_head; | ||
387 | |||
388 | /** | ||
389 | * Tail of DLL of monitor-blocked store activities. | ||
390 | */ | ||
391 | static struct StoreActivity *sa_tail; | ||
392 | |||
393 | /** | ||
394 | * Notification context shared by all monitors. | ||
395 | */ | ||
396 | static struct GNUNET_NotificationContext *monitor_nc; | ||
397 | |||
398 | /** | ||
399 | * Returned orphaned records? | ||
400 | */ | ||
401 | static int return_orphaned; | ||
402 | |||
403 | /** | ||
404 | * Task run during shutdown. | ||
405 | * | ||
406 | * @param cls unused | ||
407 | */ | ||
408 | static void | ||
409 | cleanup_task (void *cls) | ||
410 | { | ||
411 | (void) cls; | ||
412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n"); | ||
413 | if (NULL != monitor_nc) | ||
414 | { | ||
415 | GNUNET_notification_context_destroy (monitor_nc); | ||
416 | monitor_nc = NULL; | ||
417 | } | ||
418 | if (NULL != statistics) | ||
419 | { | ||
420 | GNUNET_STATISTICS_destroy (statistics, GNUNET_NO); | ||
421 | statistics = NULL; | ||
422 | } | ||
423 | GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database)); | ||
424 | GNUNET_free (db_lib_name); | ||
425 | db_lib_name = NULL; | ||
426 | } | ||
427 | |||
428 | |||
429 | /** | ||
430 | * Release memory used by @a sa. | ||
431 | * | ||
432 | * @param sa activity to free | ||
433 | */ | ||
434 | static void | ||
435 | free_store_activity (struct StoreActivity *sa) | ||
436 | { | ||
437 | GNUNET_CONTAINER_DLL_remove (sa_head, sa_tail, sa); | ||
438 | GNUNET_free (sa); | ||
439 | } | ||
440 | |||
441 | /** | ||
442 | * Function called with the records for the #GNUNET_GNS_EMPTY_LABEL_AT | ||
443 | * label in the zone. Used to locate the #GNUNET_GNSRECORD_TYPE_NICK | ||
444 | * record, which (if found) is then copied to @a cls for future use. | ||
445 | * | ||
446 | * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found) | ||
447 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
448 | * @param private_key the private key of the zone (unused) | ||
449 | * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT | ||
450 | * @param rd_count number of records in @a rd | ||
451 | * @param rd records stored under @a label in the zone | ||
452 | */ | ||
453 | static void | ||
454 | lookup_nick_it (void *cls, | ||
455 | uint64_t seq, | ||
456 | const struct GNUNET_CRYPTO_PrivateKey *private_key, | ||
457 | const char *label, | ||
458 | unsigned int rd_count, | ||
459 | const struct GNUNET_GNSRECORD_Data *rd) | ||
460 | { | ||
461 | struct GNUNET_GNSRECORD_Data **res = cls; | ||
462 | |||
463 | (void) private_key; | ||
464 | GNUNET_assert (0 != seq); | ||
465 | if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT)) | ||
466 | { | ||
467 | GNUNET_break (0); | ||
468 | return; | ||
469 | } | ||
470 | for (unsigned int c = 0; c < rd_count; c++) | ||
471 | { | ||
472 | if (GNUNET_GNSRECORD_TYPE_NICK == rd[c].record_type) | ||
473 | { | ||
474 | (*res) = | ||
475 | GNUNET_malloc (rd[c].data_size + sizeof(struct GNUNET_GNSRECORD_Data)); | ||
476 | (*res)->data = &(*res)[1]; | ||
477 | GNUNET_memcpy ((void *) (*res)->data, rd[c].data, rd[c].data_size); | ||
478 | (*res)->data_size = rd[c].data_size; | ||
479 | (*res)->expiration_time = rd[c].expiration_time; | ||
480 | (*res)->flags = rd[c].flags; | ||
481 | (*res)->record_type = GNUNET_GNSRECORD_TYPE_NICK; | ||
482 | return; | ||
483 | } | ||
484 | } | ||
485 | (*res) = NULL; | ||
486 | } | ||
487 | |||
488 | |||
489 | /** | ||
490 | * Add entry to the cache for @a zone and @a nick | ||
491 | * | ||
492 | * @param zone zone key to cache under | ||
493 | * @param nick nick entry to cache | ||
494 | */ | ||
495 | static void | ||
496 | cache_nick (const struct GNUNET_CRYPTO_PrivateKey *zone, | ||
497 | const struct GNUNET_GNSRECORD_Data *nick) | ||
498 | { | ||
499 | struct NickCache *oldest; | ||
500 | |||
501 | oldest = NULL; | ||
502 | for (unsigned int i = 0; i < NC_SIZE; i++) | ||
503 | { | ||
504 | struct NickCache *pos = &nick_cache[i]; | ||
505 | |||
506 | if ((NULL == oldest) || | ||
507 | (oldest->last_used.abs_value_us > pos->last_used.abs_value_us)) | ||
508 | oldest = pos; | ||
509 | if (0 == GNUNET_memcmp (zone, &pos->zone)) | ||
510 | { | ||
511 | oldest = pos; | ||
512 | break; | ||
513 | } | ||
514 | } | ||
515 | GNUNET_free (oldest->rd); | ||
516 | oldest->zone = *zone; | ||
517 | if (NULL != nick) | ||
518 | { | ||
519 | oldest->rd = GNUNET_malloc (sizeof(*nick) + nick->data_size); | ||
520 | *oldest->rd = *nick; | ||
521 | oldest->rd->data = &oldest->rd[1]; | ||
522 | memcpy (&oldest->rd[1], nick->data, nick->data_size); | ||
523 | } | ||
524 | else | ||
525 | { | ||
526 | oldest->rd = NULL; | ||
527 | } | ||
528 | oldest->last_used = GNUNET_TIME_absolute_get (); | ||
529 | } | ||
530 | |||
531 | |||
532 | /** | ||
533 | * Return the NICK record for the zone (if it exists). | ||
534 | * | ||
535 | * @param nc the namestore client | ||
536 | * @param zone private key for the zone to look for nick | ||
537 | * @return NULL if no NICK record was found | ||
538 | */ | ||
539 | static struct GNUNET_GNSRECORD_Data * | ||
540 | get_nick_record (const struct GNUNET_CRYPTO_PrivateKey *zone) | ||
541 | { | ||
542 | struct GNUNET_CRYPTO_PublicKey pub; | ||
543 | struct GNUNET_GNSRECORD_Data *nick; | ||
544 | int res; | ||
545 | |||
546 | /* check cache first */ | ||
547 | for (unsigned int i = 0; i < NC_SIZE; i++) | ||
548 | { | ||
549 | struct NickCache *pos = &nick_cache[i]; | ||
550 | if ((NULL != pos->rd) && (0 == GNUNET_memcmp (zone, &pos->zone))) | ||
551 | { | ||
552 | if (NULL == pos->rd) | ||
553 | return NULL; | ||
554 | nick = GNUNET_malloc (sizeof(*nick) + pos->rd->data_size); | ||
555 | *nick = *pos->rd; | ||
556 | nick->data = &nick[1]; | ||
557 | memcpy (&nick[1], pos->rd->data, pos->rd->data_size); | ||
558 | pos->last_used = GNUNET_TIME_absolute_get (); | ||
559 | return nick; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | nick = NULL; | ||
564 | res = GSN_database->lookup_records (GSN_database->cls, | ||
565 | zone, | ||
566 | GNUNET_GNS_EMPTY_LABEL_AT, | ||
567 | &lookup_nick_it, | ||
568 | &nick); | ||
569 | if ((GNUNET_OK != res) || (NULL == nick)) | ||
570 | { | ||
571 | #if ! defined(GNUNET_CULL_LOGGING) | ||
572 | static int do_log = GNUNET_LOG_CALL_STATUS; | ||
573 | |||
574 | if (0 == do_log) | ||
575 | do_log = GNUNET_get_log_call_status (GNUNET_ERROR_TYPE_DEBUG, | ||
576 | "namestore", | ||
577 | __FILE__, | ||
578 | __FUNCTION__, | ||
579 | __LINE__); | ||
580 | if (1 == do_log) | ||
581 | { | ||
582 | GNUNET_CRYPTO_key_get_public (zone, &pub); | ||
583 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
584 | "No nick name set for zone `%s'\n", | ||
585 | GNUNET_GNSRECORD_z2s (&pub)); | ||
586 | } | ||
587 | #endif | ||
588 | /* update cache */ | ||
589 | cache_nick (zone, NULL); | ||
590 | return NULL; | ||
591 | } | ||
592 | |||
593 | /* update cache */ | ||
594 | cache_nick (zone, nick); | ||
595 | return nick; | ||
596 | } | ||
597 | |||
598 | |||
599 | /** | ||
600 | * Merge the nick record @a nick_rd with the rest of the | ||
601 | * record set given in @a rd2. Store the result in @a rdc_res | ||
602 | * and @a rd_res. The @a nick_rd's expiration time is set to | ||
603 | * the maximum expiration time of all of the records in @a rd2. | ||
604 | * | ||
605 | * @param nick_rd the nick record to integrate | ||
606 | * @param rd2_length length of the @a rd2 array | ||
607 | * @param rd2 array of records | ||
608 | * @param[out] rdc_res length of the resulting @a rd_res array | ||
609 | * @param[out] rd_res set to an array of records, | ||
610 | * including @a nick_rd and @a rd2; | ||
611 | * all of the variable-size 'data' fields in @a rd2 are | ||
612 | * allocated in the same chunk of memory! | ||
613 | */ | ||
614 | static void | ||
615 | merge_with_nick_records (const struct GNUNET_GNSRECORD_Data *nick_rd, | ||
616 | unsigned int rd2_length, | ||
617 | const struct GNUNET_GNSRECORD_Data *rd2, | ||
618 | unsigned int *rdc_res, | ||
619 | struct GNUNET_GNSRECORD_Data **rd_res) | ||
620 | { | ||
621 | uint64_t latest_expiration; | ||
622 | size_t req; | ||
623 | char *data; | ||
624 | size_t data_offset; | ||
625 | struct GNUNET_GNSRECORD_Data *target; | ||
626 | |||
627 | (*rdc_res) = 1 + rd2_length; | ||
628 | if (0 == 1 + rd2_length) | ||
629 | { | ||
630 | GNUNET_break (0); | ||
631 | (*rd_res) = NULL; | ||
632 | return; | ||
633 | } | ||
634 | req = sizeof(struct GNUNET_GNSRECORD_Data) + nick_rd->data_size; | ||
635 | for (unsigned int i = 0; i < rd2_length; i++) | ||
636 | { | ||
637 | const struct GNUNET_GNSRECORD_Data *orig = &rd2[i]; | ||
638 | |||
639 | if (req + sizeof(struct GNUNET_GNSRECORD_Data) + orig->data_size < req) | ||
640 | { | ||
641 | GNUNET_break (0); | ||
642 | (*rd_res) = NULL; | ||
643 | return; | ||
644 | } | ||
645 | req += sizeof(struct GNUNET_GNSRECORD_Data) + orig->data_size; | ||
646 | } | ||
647 | target = GNUNET_malloc (req); | ||
648 | (*rd_res) = target; | ||
649 | data = (char *) &target[1 + rd2_length]; | ||
650 | data_offset = 0; | ||
651 | latest_expiration = 0; | ||
652 | for (unsigned int i = 0; i < rd2_length; i++) | ||
653 | { | ||
654 | const struct GNUNET_GNSRECORD_Data *orig = &rd2[i]; | ||
655 | |||
656 | if (0 != (orig->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) | ||
657 | { | ||
658 | if ((GNUNET_TIME_absolute_get ().abs_value_us + orig->expiration_time) > | ||
659 | latest_expiration) | ||
660 | latest_expiration = orig->expiration_time; | ||
661 | } | ||
662 | else if (orig->expiration_time > latest_expiration) | ||
663 | latest_expiration = orig->expiration_time; | ||
664 | target[i] = *orig; | ||
665 | target[i].data = (void *) &data[data_offset]; | ||
666 | GNUNET_memcpy (&data[data_offset], orig->data, orig->data_size); | ||
667 | data_offset += orig->data_size; | ||
668 | } | ||
669 | /* append nick */ | ||
670 | target[rd2_length] = *nick_rd; | ||
671 | /* Mark as supplemental */ | ||
672 | target[rd2_length].flags = nick_rd->flags | GNUNET_GNSRECORD_RF_SUPPLEMENTAL; | ||
673 | target[rd2_length].expiration_time = latest_expiration; | ||
674 | target[rd2_length].data = (void *) &data[data_offset]; | ||
675 | GNUNET_memcpy (&data[data_offset], nick_rd->data, nick_rd->data_size); | ||
676 | data_offset += nick_rd->data_size; | ||
677 | GNUNET_assert (req == (sizeof(struct GNUNET_GNSRECORD_Data)) * (*rdc_res) | ||
678 | + data_offset); | ||
679 | } | ||
680 | |||
681 | |||
682 | /** | ||
683 | * Generate a `struct LookupNameResponseMessage` and send it to the | ||
684 | * given client using the given notification context. | ||
685 | * | ||
686 | * @param nc client to unicast to | ||
687 | * @param request_id request ID to use | ||
688 | * @param zone_key zone key of the zone | ||
689 | * @param name name | ||
690 | * @param rd_count number of records in @a rd | ||
691 | * @param rd array of records | ||
692 | * @param filter record set filter | ||
693 | */ | ||
694 | static int | ||
695 | send_lookup_response_with_filter (struct NamestoreClient *nc, | ||
696 | uint32_t request_id, | ||
697 | const struct | ||
698 | GNUNET_CRYPTO_PrivateKey *zone_key, | ||
699 | const char *name, | ||
700 | unsigned int rd_count, | ||
701 | const struct GNUNET_GNSRECORD_Data *rd, | ||
702 | enum GNUNET_GNSRECORD_Filter filter) | ||
703 | { | ||
704 | struct GNUNET_MQ_Envelope *env; | ||
705 | struct RecordResultMessage *zir_msg; | ||
706 | struct GNUNET_GNSRECORD_Data *nick; | ||
707 | struct GNUNET_GNSRECORD_Data *res; | ||
708 | struct GNUNET_GNSRECORD_Data rd_nf[rd_count]; | ||
709 | struct GNUNET_TIME_Absolute block_exp = GNUNET_TIME_UNIT_ZERO_ABS;; | ||
710 | unsigned int res_count; | ||
711 | unsigned int rd_nf_count; | ||
712 | size_t name_len; | ||
713 | size_t key_len; | ||
714 | ssize_t rd_ser_len; | ||
715 | char *name_tmp; | ||
716 | char *rd_ser; | ||
717 | char *emsg; | ||
718 | |||
719 | nick = get_nick_record (zone_key); | ||
720 | GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd)); | ||
721 | |||
722 | if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (name, | ||
723 | rd, | ||
724 | rd_count, | ||
725 | rd_nf, | ||
726 | &rd_nf_count, | ||
727 | &block_exp, | ||
728 | filter, | ||
729 | &emsg)) | ||
730 | { | ||
731 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); | ||
732 | GNUNET_free (emsg); | ||
733 | GNUNET_assert (0); | ||
734 | } | ||
735 | |||
736 | /** | ||
737 | * FIXME if we ever support GNUNET_NAMESTORE_OMIT_PUBLIC, | ||
738 | * we need to omit adding this public record here | ||
739 | */ | ||
740 | if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) | ||
741 | { | ||
742 | nick->flags = | ||
743 | (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE; | ||
744 | merge_with_nick_records (nick, rd_nf_count, rd_nf, &res_count, &res); | ||
745 | } | ||
746 | else | ||
747 | { | ||
748 | res_count = rd_nf_count; | ||
749 | res = (struct GNUNET_GNSRECORD_Data *) rd_nf; | ||
750 | } | ||
751 | if (NULL != nick) | ||
752 | GNUNET_free (nick); | ||
753 | |||
754 | if (0 == res_count) | ||
755 | { | ||
756 | if (rd_nf != res) | ||
757 | GNUNET_free (res); | ||
758 | return 0; | ||
759 | } | ||
760 | GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (res_count, res)); | ||
761 | |||
762 | |||
763 | name_len = strlen (name) + 1; | ||
764 | rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res); | ||
765 | if (rd_ser_len < 0) | ||
766 | { | ||
767 | if (rd_nf != res) | ||
768 | GNUNET_free (res); | ||
769 | GNUNET_break (0); | ||
770 | GNUNET_SERVICE_client_drop (nc->client); | ||
771 | return 0; | ||
772 | } | ||
773 | if (((size_t) rd_ser_len) >= UINT16_MAX - name_len - sizeof(*zir_msg)) | ||
774 | { | ||
775 | if (rd_nf != res) | ||
776 | GNUNET_free (res); | ||
777 | GNUNET_break (0); | ||
778 | GNUNET_SERVICE_client_drop (nc->client); | ||
779 | return 0; | ||
780 | } | ||
781 | key_len = GNUNET_CRYPTO_private_key_get_length (zone_key); | ||
782 | env = GNUNET_MQ_msg_extra (zir_msg, | ||
783 | name_len + rd_ser_len + key_len, | ||
784 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT); | ||
785 | zir_msg->gns_header.r_id = htonl (request_id); | ||
786 | zir_msg->name_len = htons (name_len); | ||
787 | zir_msg->rd_count = htons (res_count); | ||
788 | zir_msg->rd_len = htons ((uint16_t) rd_ser_len); | ||
789 | zir_msg->key_len = htons (key_len); | ||
790 | GNUNET_CRYPTO_write_private_key_to_buffer (zone_key, | ||
791 | &zir_msg[1], | ||
792 | key_len); | ||
793 | zir_msg->expire = GNUNET_TIME_absolute_hton (block_exp); | ||
794 | name_tmp = (char *) &zir_msg[1] + key_len; | ||
795 | GNUNET_memcpy (name_tmp, name, name_len); | ||
796 | rd_ser = &name_tmp[name_len]; | ||
797 | GNUNET_assert ( | ||
798 | rd_ser_len == | ||
799 | GNUNET_GNSRECORD_records_serialize (res_count, res, rd_ser_len, rd_ser)); | ||
800 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
801 | "Sending RECORD_RESULT message with %u records\n", | ||
802 | res_count); | ||
803 | GNUNET_STATISTICS_update (statistics, | ||
804 | "Record sets sent to clients", | ||
805 | 1, | ||
806 | GNUNET_NO); | ||
807 | GNUNET_MQ_send (nc->mq, env); | ||
808 | if (rd_nf != res) | ||
809 | GNUNET_free (res); | ||
810 | return res_count; | ||
811 | } | ||
812 | |||
813 | /** | ||
814 | * Send response to the store request to the client. | ||
815 | * | ||
816 | * @param nc client to talk to | ||
817 | * @param ec status of the operation | ||
818 | * @param rid client's request ID | ||
819 | */ | ||
820 | static void | ||
821 | send_store_response (struct NamestoreClient *nc, | ||
822 | enum GNUNET_ErrorCode ec, | ||
823 | uint32_t rid) | ||
824 | { | ||
825 | struct GNUNET_MQ_Envelope *env; | ||
826 | struct RecordStoreResponseMessage *rcr_msg; | ||
827 | |||
828 | GNUNET_assert (NULL != nc); | ||
829 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
830 | "Sending RECORD_STORE_RESPONSE message\n"); | ||
831 | GNUNET_STATISTICS_update (statistics, | ||
832 | "Store requests completed", | ||
833 | 1, | ||
834 | GNUNET_NO); | ||
835 | env = GNUNET_MQ_msg (rcr_msg, | ||
836 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE); | ||
837 | rcr_msg->gns_header.r_id = htonl (rid); | ||
838 | rcr_msg->ec = htonl (ec); | ||
839 | GNUNET_MQ_send (nc->mq, env); | ||
840 | } | ||
841 | |||
842 | |||
843 | /** | ||
844 | * Function called once we are done with the zone iteration and | ||
845 | * allow the zone iteration client to send us more messages. | ||
846 | * | ||
847 | * @param zi zone iteration we are processing | ||
848 | */ | ||
849 | static void | ||
850 | zone_iteration_done_client_continue (struct ZoneIteration *zi) | ||
851 | { | ||
852 | struct GNUNET_MQ_Envelope *env; | ||
853 | struct GNUNET_NAMESTORE_Header *em; | ||
854 | |||
855 | GNUNET_SERVICE_client_continue (zi->nc->client); | ||
856 | if (! zi->send_end) | ||
857 | return; | ||
858 | /* send empty response to indicate end of list */ | ||
859 | env = GNUNET_MQ_msg (em, GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END); | ||
860 | em->r_id = htonl (zi->request_id); | ||
861 | GNUNET_MQ_send (zi->nc->mq, env); | ||
862 | |||
863 | GNUNET_CONTAINER_DLL_remove (zi->nc->op_head, zi->nc->op_tail, zi); | ||
864 | GNUNET_free (zi); | ||
865 | } | ||
866 | |||
867 | |||
868 | |||
869 | |||
870 | /** | ||
871 | * Print a warning that one of our monitors is no longer reacting. | ||
872 | * | ||
873 | * @param cls a `struct ZoneMonitor` to warn about | ||
874 | */ | ||
875 | static void | ||
876 | warn_monitor_slow (void *cls) | ||
877 | { | ||
878 | struct ZoneMonitor *zm = cls; | ||
879 | |||
880 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
881 | "No response from monitor since %s\n", | ||
882 | GNUNET_STRINGS_absolute_time_to_string (zm->sa_waiting_start)); | ||
883 | zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
884 | &warn_monitor_slow, | ||
885 | zm); | ||
886 | } | ||
887 | |||
888 | |||
889 | /** | ||
890 | * Continue processing the @a sa. | ||
891 | * | ||
892 | * @param sa store activity to process | ||
893 | */ | ||
894 | static int | ||
895 | continue_store_activity (struct StoreActivity *sa, | ||
896 | int call_continue) | ||
897 | { | ||
898 | const struct RecordSet *rd_set = sa->rs; | ||
899 | unsigned int rd_count; | ||
900 | size_t name_len; | ||
901 | size_t rd_ser_len; | ||
902 | const char *name_tmp; | ||
903 | const char *rd_ser; | ||
904 | const char *buf; | ||
905 | char *conv_name; | ||
906 | |||
907 | // If we are in a transaction, do not notify monitors or update | ||
908 | // cached. This will be done when we are commiting. | ||
909 | if (GNUNET_YES == sa->uncommited) | ||
910 | { | ||
911 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
912 | "Transaction not yet committed, delaying monitor and cache updates\n"); | ||
913 | send_store_response (sa->nc, GNUNET_EC_NONE, sa->rid); | ||
914 | if (GNUNET_YES == call_continue) | ||
915 | GNUNET_SERVICE_client_continue (sa->nc->client); | ||
916 | return GNUNET_OK; | ||
917 | } | ||
918 | buf = (const char *) &sa[1]; | ||
919 | for (int i = sa->rd_set_pos; i < sa->rd_set_count; i++) | ||
920 | { | ||
921 | rd_set = (struct RecordSet *) buf; | ||
922 | name_len = ntohs (rd_set->name_len); | ||
923 | rd_count = ntohs (rd_set->rd_count); | ||
924 | rd_ser_len = ntohs (rd_set->rd_len); | ||
925 | name_tmp = (const char *) &rd_set[1]; | ||
926 | rd_ser = &name_tmp[name_len]; | ||
927 | conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp); | ||
928 | GNUNET_assert (NULL != conv_name); | ||
929 | { | ||
930 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; | ||
931 | |||
932 | /* We did this before, must succeed again */ | ||
933 | GNUNET_assert ( | ||
934 | GNUNET_OK == | ||
935 | GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, | ||
936 | rd)); | ||
937 | |||
938 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
939 | "Checking monitors watching for `%s'\n", | ||
940 | conv_name); | ||
941 | for (struct ZoneMonitor *zm = sa->zm_pos; NULL != zm; zm = sa->zm_pos) | ||
942 | { | ||
943 | if ((0 != GNUNET_memcmp (&sa->private_key, &zm->zone)) && | ||
944 | (0 != GNUNET_memcmp (&zm->zone, &zero))) | ||
945 | { | ||
946 | sa->zm_pos = zm->next; /* not interesting to this monitor */ | ||
947 | continue; | ||
948 | } | ||
949 | if (zm->limit == zm->iteration_cnt) | ||
950 | { | ||
951 | zm->sa_waiting = GNUNET_YES; | ||
952 | zm->sa_waiting_start = GNUNET_TIME_absolute_get (); | ||
953 | if (NULL != zm->sa_wait_warning) | ||
954 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
955 | zm->sa_wait_warning = | ||
956 | GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
957 | &warn_monitor_slow, | ||
958 | zm); | ||
959 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
960 | "Monitor is blocking client for `%s'\n", | ||
961 | conv_name); | ||
962 | GNUNET_free (conv_name); | ||
963 | return GNUNET_NO; /* blocked on zone monitor */ | ||
964 | } | ||
965 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
966 | "Notifying monitor about changes under label `%s'\n", | ||
967 | conv_name); | ||
968 | if (0 < send_lookup_response_with_filter (zm->nc, | ||
969 | 0, | ||
970 | &sa->private_key, | ||
971 | conv_name, | ||
972 | rd_count, | ||
973 | rd, | ||
974 | zm->filter)) | ||
975 | zm->limit--; | ||
976 | sa->zm_pos = zm->next; | ||
977 | } | ||
978 | sa->rd_set_pos++; | ||
979 | GNUNET_free (conv_name); | ||
980 | } | ||
981 | } | ||
982 | if (GNUNET_YES == call_continue) | ||
983 | GNUNET_SERVICE_client_continue (sa->nc->client); | ||
984 | send_store_response (sa->nc, GNUNET_EC_NONE, sa->rid); | ||
985 | free_store_activity (sa); | ||
986 | return GNUNET_OK; | ||
987 | } | ||
988 | |||
989 | |||
990 | /** | ||
991 | * Called whenever a client is disconnected. | ||
992 | * Frees our resources associated with that client. | ||
993 | * | ||
994 | * @param cls closure | ||
995 | * @param client identification of the client | ||
996 | * @param app_ctx the `struct NamestoreClient` of @a client | ||
997 | */ | ||
998 | static void | ||
999 | client_disconnect_cb (void *cls, | ||
1000 | struct GNUNET_SERVICE_Client *client, | ||
1001 | void *app_ctx) | ||
1002 | { | ||
1003 | struct NamestoreClient *nc = app_ctx; | ||
1004 | struct ZoneIteration *no; | ||
1005 | struct StoreActivity *sa = sa_head; | ||
1006 | struct StoreActivity *sn; | ||
1007 | char *emsg; | ||
1008 | |||
1009 | (void) cls; | ||
1010 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client); | ||
1011 | if (GNUNET_YES == nc->in_transaction) | ||
1012 | { | ||
1013 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1014 | "Client in transaction, rolling back...\n"); | ||
1015 | if (GNUNET_SYSERR == nc->GSN_database->transaction_rollback ( | ||
1016 | nc->GSN_database->cls, | ||
1017 | &emsg)) | ||
1018 | { | ||
1019 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1020 | "Unable to roll back: %s\n", emsg); | ||
1021 | GNUNET_free (emsg); | ||
1022 | } | ||
1023 | else | ||
1024 | { | ||
1025 | nc->in_transaction = GNUNET_NO; | ||
1026 | while (NULL != sa) | ||
1027 | { | ||
1028 | if ((nc != sa->nc) || | ||
1029 | (GNUNET_NO == sa->uncommited)) | ||
1030 | { | ||
1031 | sa = sa->next; | ||
1032 | continue; | ||
1033 | } | ||
1034 | sn = sa->next; | ||
1035 | free_store_activity (sa); | ||
1036 | sa = sn; | ||
1037 | } | ||
1038 | } | ||
1039 | } | ||
1040 | for (struct ZoneMonitor *zm = monitor_head; NULL != zm; zm = zm->next) | ||
1041 | { | ||
1042 | if (nc != zm->nc) | ||
1043 | continue; | ||
1044 | GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, zm); | ||
1045 | if (NULL != zm->task) | ||
1046 | { | ||
1047 | GNUNET_SCHEDULER_cancel (zm->task); | ||
1048 | zm->task = NULL; | ||
1049 | } | ||
1050 | if (NULL != zm->sa_wait_warning) | ||
1051 | { | ||
1052 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
1053 | zm->sa_wait_warning = NULL; | ||
1054 | } | ||
1055 | for (sa = sa_head; NULL != sa; sa = sn) | ||
1056 | { | ||
1057 | sn = sa->next; | ||
1058 | if (zm == sa->zm_pos) | ||
1059 | { | ||
1060 | sa->zm_pos = zm->next; | ||
1061 | /* this may free sa */ | ||
1062 | continue_store_activity (sa, GNUNET_YES); | ||
1063 | } | ||
1064 | } | ||
1065 | GNUNET_free (zm); | ||
1066 | break; | ||
1067 | } | ||
1068 | sa = sa_head; | ||
1069 | while (NULL != sa) | ||
1070 | { | ||
1071 | if (nc != sa->nc) | ||
1072 | { | ||
1073 | sa = sa->next; | ||
1074 | continue; | ||
1075 | } | ||
1076 | sn = sa->next; | ||
1077 | free_store_activity (sa); | ||
1078 | sa = sn; | ||
1079 | } | ||
1080 | while (NULL != (no = nc->op_head)) | ||
1081 | { | ||
1082 | GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no); | ||
1083 | GNUNET_free (no); | ||
1084 | } | ||
1085 | GNUNET_break (NULL == GNUNET_PLUGIN_unload (nc->db_lib_name, | ||
1086 | nc->GSN_database)); | ||
1087 | GNUNET_free (nc->db_lib_name); | ||
1088 | GNUNET_free (nc); | ||
1089 | } | ||
1090 | |||
1091 | |||
1092 | /** | ||
1093 | * Add a client to our list of active clients. | ||
1094 | * | ||
1095 | * @param cls NULL | ||
1096 | * @param client client to add | ||
1097 | * @param mq message queue for @a client | ||
1098 | * @return internal namestore client structure for this client | ||
1099 | */ | ||
1100 | static void * | ||
1101 | client_connect_cb (void *cls, | ||
1102 | struct GNUNET_SERVICE_Client *client, | ||
1103 | struct GNUNET_MQ_Handle *mq) | ||
1104 | { | ||
1105 | struct NamestoreClient *nc; | ||
1106 | char *database; | ||
1107 | |||
1108 | (void) cls; | ||
1109 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); | ||
1110 | nc = GNUNET_new (struct NamestoreClient); | ||
1111 | nc->client = client; | ||
1112 | nc->mq = mq; | ||
1113 | /* Loading database plugin */ | ||
1114 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (GSN_cfg, | ||
1115 | "namestore", | ||
1116 | "database", | ||
1117 | &database)) | ||
1118 | { | ||
1119 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); | ||
1120 | GNUNET_free (nc); | ||
1121 | return NULL; | ||
1122 | } | ||
1123 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name); | ||
1124 | nc->GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg); | ||
1125 | GNUNET_free (database); | ||
1126 | if (NULL == nc->GSN_database) | ||
1127 | { | ||
1128 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1129 | "Could not load database backend `%s'\n", | ||
1130 | db_lib_name); | ||
1131 | GNUNET_free (nc); | ||
1132 | return NULL; | ||
1133 | } | ||
1134 | nc->db_lib_name = GNUNET_strdup (db_lib_name); | ||
1135 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded %s\n", db_lib_name); | ||
1136 | return nc; | ||
1137 | } | ||
1138 | |||
1139 | |||
1140 | /** | ||
1141 | * Closure for #lookup_it(). | ||
1142 | */ | ||
1143 | struct RecordLookupContext | ||
1144 | { | ||
1145 | /** | ||
1146 | * The label to look up. | ||
1147 | */ | ||
1148 | const char *label; | ||
1149 | |||
1150 | /** | ||
1151 | * The record result. | ||
1152 | */ | ||
1153 | char *res_rd; | ||
1154 | |||
1155 | /** | ||
1156 | * The nick for the zone. | ||
1157 | */ | ||
1158 | struct GNUNET_GNSRECORD_Data *nick; | ||
1159 | |||
1160 | /** | ||
1161 | * If a record set was found or not. | ||
1162 | */ | ||
1163 | int found; | ||
1164 | |||
1165 | /** | ||
1166 | * The record filter | ||
1167 | */ | ||
1168 | enum GNUNET_GNSRECORD_Filter filter; | ||
1169 | |||
1170 | /** | ||
1171 | * The number of found records. | ||
1172 | */ | ||
1173 | unsigned int res_rd_count; | ||
1174 | |||
1175 | /** | ||
1176 | * The length of the serialized records. | ||
1177 | */ | ||
1178 | ssize_t rd_ser_len; | ||
1179 | }; | ||
1180 | |||
1181 | |||
1182 | /** | ||
1183 | * Function called by the namestore plugin when we are trying to lookup | ||
1184 | * a record as part of #handle_record_lookup(). Merges all results into | ||
1185 | * the context. | ||
1186 | * | ||
1187 | * @param cls closure with a `struct RecordLookupContext` | ||
1188 | * @param seq unique serial number of the record, MUST NOT BE ZERO | ||
1189 | * @param private_key private key of the zone | ||
1190 | * @param label name that is being mapped (at most 255 characters long) | ||
1191 | * @param rd_count number of entries in @a rd array | ||
1192 | * @param rd array of records with data to store | ||
1193 | */ | ||
1194 | static void | ||
1195 | lookup_it (void *cls, | ||
1196 | uint64_t seq, | ||
1197 | const struct GNUNET_CRYPTO_PrivateKey *private_key, | ||
1198 | const char *label, | ||
1199 | unsigned int rd_count_nf, | ||
1200 | const struct GNUNET_GNSRECORD_Data *rd_nf) | ||
1201 | { | ||
1202 | struct RecordLookupContext *rlc = cls; | ||
1203 | struct GNUNET_GNSRECORD_Data rd[rd_count_nf]; | ||
1204 | struct GNUNET_TIME_Absolute block_exp; | ||
1205 | unsigned int rd_count = 0; | ||
1206 | char *emsg; | ||
1207 | |||
1208 | (void) private_key; | ||
1209 | GNUNET_assert (0 != seq); | ||
1210 | if (0 != strcmp (label, rlc->label)) | ||
1211 | return; | ||
1212 | rlc->found = GNUNET_YES; | ||
1213 | |||
1214 | if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (rlc->label, | ||
1215 | rd_nf, | ||
1216 | rd_count_nf, | ||
1217 | rd, | ||
1218 | &rd_count, | ||
1219 | &block_exp, | ||
1220 | rlc->filter, | ||
1221 | &emsg)) | ||
1222 | { | ||
1223 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); | ||
1224 | GNUNET_free (emsg); | ||
1225 | GNUNET_assert (0); | ||
1226 | } | ||
1227 | |||
1228 | if (0 == rd_count) | ||
1229 | { | ||
1230 | rlc->rd_ser_len = 0; | ||
1231 | rlc->res_rd_count = 0; | ||
1232 | rlc->res_rd = NULL; | ||
1233 | return; | ||
1234 | } | ||
1235 | if ((NULL != rlc->nick) && (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))) | ||
1236 | { | ||
1237 | /* Merge */ | ||
1238 | struct GNUNET_GNSRECORD_Data *rd_res; | ||
1239 | unsigned int rdc_res; | ||
1240 | |||
1241 | rd_res = NULL; | ||
1242 | rdc_res = 0; | ||
1243 | rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) | ||
1244 | ^ GNUNET_GNSRECORD_RF_PRIVATE; | ||
1245 | merge_with_nick_records (rlc->nick, rd_count, rd, &rdc_res, &rd_res); | ||
1246 | rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res, rd_res); | ||
1247 | if (rlc->rd_ser_len < 0) | ||
1248 | { | ||
1249 | GNUNET_break (0); | ||
1250 | GNUNET_free (rd_res); | ||
1251 | rlc->found = GNUNET_NO; | ||
1252 | rlc->rd_ser_len = 0; | ||
1253 | return; | ||
1254 | } | ||
1255 | rlc->res_rd_count = rdc_res; | ||
1256 | rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len); | ||
1257 | if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rdc_res, | ||
1258 | rd_res, | ||
1259 | rlc->rd_ser_len, | ||
1260 | rlc->res_rd)) | ||
1261 | { | ||
1262 | GNUNET_break (0); | ||
1263 | GNUNET_free (rlc->res_rd); | ||
1264 | rlc->res_rd = NULL; | ||
1265 | rlc->res_rd_count = 0; | ||
1266 | rlc->rd_ser_len = 0; | ||
1267 | GNUNET_free (rd_res); | ||
1268 | rlc->found = GNUNET_NO; | ||
1269 | return; | ||
1270 | } | ||
1271 | GNUNET_free (rd_res); | ||
1272 | GNUNET_free (rlc->nick); | ||
1273 | rlc->nick = NULL; | ||
1274 | } | ||
1275 | else | ||
1276 | { | ||
1277 | rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | ||
1278 | if (rlc->rd_ser_len < 0) | ||
1279 | { | ||
1280 | GNUNET_break (0); | ||
1281 | rlc->found = GNUNET_NO; | ||
1282 | rlc->rd_ser_len = 0; | ||
1283 | return; | ||
1284 | } | ||
1285 | rlc->res_rd_count = rd_count; | ||
1286 | rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len); | ||
1287 | if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rd_count, | ||
1288 | rd, | ||
1289 | rlc->rd_ser_len, | ||
1290 | rlc->res_rd)) | ||
1291 | { | ||
1292 | GNUNET_break (0); | ||
1293 | GNUNET_free (rlc->res_rd); | ||
1294 | rlc->res_rd = NULL; | ||
1295 | rlc->res_rd_count = 0; | ||
1296 | rlc->rd_ser_len = 0; | ||
1297 | rlc->found = GNUNET_NO; | ||
1298 | return; | ||
1299 | } | ||
1300 | } | ||
1301 | } | ||
1302 | |||
1303 | |||
1304 | /** | ||
1305 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message | ||
1306 | * | ||
1307 | * @param cls client sending the message | ||
1308 | * @param ll_msg message of type `struct LabelLookupMessage` | ||
1309 | * @return #GNUNET_OK if @a ll_msg is well-formed | ||
1310 | */ | ||
1311 | static int | ||
1312 | check_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | ||
1313 | { | ||
1314 | uint32_t name_len; | ||
1315 | size_t src_size; | ||
1316 | size_t key_len; | ||
1317 | |||
1318 | (void) cls; | ||
1319 | name_len = ntohs (ll_msg->label_len); | ||
1320 | key_len = ntohs (ll_msg->key_len); | ||
1321 | src_size = ntohs (ll_msg->gns_header.header.size); | ||
1322 | if (name_len + key_len != src_size - sizeof(struct LabelLookupMessage)) | ||
1323 | { | ||
1324 | GNUNET_break (0); | ||
1325 | return GNUNET_SYSERR; | ||
1326 | } | ||
1327 | return GNUNET_OK; | ||
1328 | } | ||
1329 | |||
1330 | |||
1331 | /** | ||
1332 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message | ||
1333 | * | ||
1334 | * @param cls client sending the message | ||
1335 | * @param ll_msg message of type `struct LabelLookupMessage` | ||
1336 | */ | ||
1337 | static void | ||
1338 | handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | ||
1339 | { | ||
1340 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
1341 | struct NamestoreClient *nc = cls; | ||
1342 | struct GNUNET_MQ_Envelope *env; | ||
1343 | struct LabelLookupResponseMessage *llr_msg; | ||
1344 | struct RecordLookupContext rlc; | ||
1345 | const char *name_tmp; | ||
1346 | char *res_name; | ||
1347 | char *conv_name; | ||
1348 | uint32_t name_len; | ||
1349 | int res; | ||
1350 | size_t key_len; | ||
1351 | size_t kb_read; | ||
1352 | |||
1353 | key_len = ntohs (ll_msg->key_len); | ||
1354 | if ((GNUNET_SYSERR == | ||
1355 | GNUNET_CRYPTO_read_private_key_from_buffer (&ll_msg[1], | ||
1356 | key_len, | ||
1357 | &zone, | ||
1358 | &kb_read)) || | ||
1359 | (kb_read != key_len)) | ||
1360 | { | ||
1361 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1362 | "Error reading private key\n"); | ||
1363 | GNUNET_SERVICE_client_drop (nc->client); | ||
1364 | return; | ||
1365 | } | ||
1366 | name_tmp = (const char *) &ll_msg[1] + key_len; | ||
1367 | GNUNET_SERVICE_client_continue (nc->client); | ||
1368 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1369 | "Received NAMESTORE_RECORD_LOOKUP message for name `%s'\n", | ||
1370 | name_tmp); | ||
1371 | |||
1372 | conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp); | ||
1373 | if (NULL == conv_name) | ||
1374 | { | ||
1375 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1376 | "Error converting name `%s'\n", | ||
1377 | name_tmp); | ||
1378 | GNUNET_SERVICE_client_drop (nc->client); | ||
1379 | return; | ||
1380 | } | ||
1381 | name_len = strlen (conv_name) + 1; | ||
1382 | rlc.label = conv_name; | ||
1383 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1384 | "Looking up with filter %u\n", ntohs (ll_msg->filter)); | ||
1385 | rlc.filter = ntohs (ll_msg->filter); | ||
1386 | rlc.found = GNUNET_NO; | ||
1387 | rlc.res_rd_count = 0; | ||
1388 | rlc.res_rd = NULL; | ||
1389 | rlc.rd_ser_len = 0; | ||
1390 | rlc.nick = get_nick_record (&zone); | ||
1391 | if (GNUNET_YES != ntohs (ll_msg->is_edit_request)) | ||
1392 | res = nc->GSN_database->lookup_records (nc->GSN_database->cls, | ||
1393 | &zone, | ||
1394 | conv_name, | ||
1395 | &lookup_it, | ||
1396 | &rlc); | ||
1397 | else | ||
1398 | res = nc->GSN_database->edit_records (nc->GSN_database->cls, | ||
1399 | &zone, | ||
1400 | conv_name, | ||
1401 | &lookup_it, | ||
1402 | &rlc); | ||
1403 | |||
1404 | env = | ||
1405 | GNUNET_MQ_msg_extra (llr_msg, | ||
1406 | key_len + name_len + rlc.rd_ser_len, | ||
1407 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE); | ||
1408 | llr_msg->gns_header.r_id = ll_msg->gns_header.r_id; | ||
1409 | GNUNET_memcpy (&llr_msg[1], &ll_msg[1], key_len); | ||
1410 | llr_msg->key_len = ll_msg->key_len; | ||
1411 | llr_msg->name_len = htons (name_len); | ||
1412 | llr_msg->rd_count = htons (rlc.res_rd_count); | ||
1413 | llr_msg->rd_len = htons (rlc.rd_ser_len); | ||
1414 | llr_msg->reserved = htons (0); | ||
1415 | res_name = ((char *) &llr_msg[1]) + key_len; | ||
1416 | if (GNUNET_YES == rlc.found) | ||
1417 | llr_msg->found = htons (GNUNET_YES); | ||
1418 | else if (GNUNET_SYSERR == res) | ||
1419 | llr_msg->found = htons (GNUNET_SYSERR); | ||
1420 | else | ||
1421 | llr_msg->found = htons (GNUNET_NO); | ||
1422 | GNUNET_memcpy (res_name, conv_name, name_len); | ||
1423 | GNUNET_memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len); | ||
1424 | GNUNET_MQ_send (nc->mq, env); | ||
1425 | GNUNET_free (rlc.res_rd); | ||
1426 | GNUNET_free (conv_name); | ||
1427 | } | ||
1428 | |||
1429 | |||
1430 | |||
1431 | /** | ||
1432 | * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message | ||
1433 | * | ||
1434 | * @param cls client sending the message | ||
1435 | * @param rp_msg message of type `struct RecordStoreMessage` | ||
1436 | * @return #GNUNET_OK if @a rp_msg is well-formed | ||
1437 | */ | ||
1438 | static int | ||
1439 | check_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | ||
1440 | { | ||
1441 | size_t msg_size; | ||
1442 | size_t min_size_exp; | ||
1443 | size_t rd_set_count; | ||
1444 | size_t key_len; | ||
1445 | |||
1446 | (void) cls; | ||
1447 | msg_size = ntohs (rp_msg->gns_header.header.size); | ||
1448 | rd_set_count = ntohs (rp_msg->rd_set_count); | ||
1449 | key_len = ntohs (rp_msg->key_len); | ||
1450 | |||
1451 | min_size_exp = sizeof(*rp_msg) + key_len + sizeof (struct RecordSet) | ||
1452 | * rd_set_count; | ||
1453 | if (msg_size < min_size_exp) | ||
1454 | { | ||
1455 | GNUNET_break (0); | ||
1456 | return GNUNET_SYSERR; | ||
1457 | } | ||
1458 | return GNUNET_OK; | ||
1459 | } | ||
1460 | |||
1461 | struct LookupExistingRecordsContext | ||
1462 | { | ||
1463 | |||
1464 | /** | ||
1465 | * The expiration of the existing records or tombstone | ||
1466 | */ | ||
1467 | struct GNUNET_TIME_Absolute exp; | ||
1468 | |||
1469 | /** | ||
1470 | * Whether the existing record set consists only of a tombstone | ||
1471 | * (e.g. is "empty") | ||
1472 | */ | ||
1473 | int only_tombstone; | ||
1474 | |||
1475 | }; | ||
1476 | |||
1477 | |||
1478 | /** | ||
1479 | * Check if set contains a tombstone, store if necessary | ||
1480 | * | ||
1481 | * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found) | ||
1482 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
1483 | * @param private_key the private key of the zone (unused) | ||
1484 | * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT | ||
1485 | * @param rd_count number of records in @a rd | ||
1486 | * @param rd records stored under @a label in the zone | ||
1487 | */ | ||
1488 | static void | ||
1489 | get_existing_rd_exp (void *cls, | ||
1490 | uint64_t seq, | ||
1491 | const struct | ||
1492 | GNUNET_CRYPTO_PrivateKey *private_key, | ||
1493 | const char *label, | ||
1494 | unsigned int rd_count, | ||
1495 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1496 | { | ||
1497 | struct LookupExistingRecordsContext *lctx = cls; | ||
1498 | struct GNUNET_GNSRECORD_Data rd_pub[rd_count]; | ||
1499 | unsigned int rd_pub_count; | ||
1500 | char *emsg; | ||
1501 | |||
1502 | if ((1 == rd_count) && | ||
1503 | (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[0].record_type)) | ||
1504 | { | ||
1505 | /* This record set contains only a tombstone! */ | ||
1506 | lctx->only_tombstone = GNUNET_YES; | ||
1507 | } | ||
1508 | if (GNUNET_OK != | ||
1509 | GNUNET_GNSRECORD_normalize_record_set (label, | ||
1510 | rd, | ||
1511 | rd_count, | ||
1512 | rd_pub, | ||
1513 | &rd_pub_count, | ||
1514 | &lctx->exp, | ||
1515 | GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE, | ||
1516 | &emsg)) | ||
1517 | { | ||
1518 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1519 | "%s\n", emsg); | ||
1520 | GNUNET_free (emsg); | ||
1521 | } | ||
1522 | } | ||
1523 | |||
1524 | static enum GNUNET_ErrorCode | ||
1525 | store_record_set (struct NamestoreClient *nc, | ||
1526 | const struct GNUNET_CRYPTO_PrivateKey *private_key, | ||
1527 | const struct RecordSet *rd_set, | ||
1528 | ssize_t *len) | ||
1529 | { | ||
1530 | size_t name_len; | ||
1531 | size_t rd_ser_len; | ||
1532 | const char *name_tmp; | ||
1533 | const char *rd_ser; | ||
1534 | char *conv_name; | ||
1535 | char *emsg; | ||
1536 | unsigned int rd_count; | ||
1537 | int res; | ||
1538 | enum GNUNET_ErrorCode ec; | ||
1539 | struct GNUNET_TIME_Absolute new_block_exp; | ||
1540 | struct LookupExistingRecordsContext lctx; | ||
1541 | *len = sizeof (struct RecordSet); | ||
1542 | |||
1543 | ec = GNUNET_EC_NONE; | ||
1544 | lctx.only_tombstone = GNUNET_NO; | ||
1545 | lctx.exp = GNUNET_TIME_UNIT_ZERO_ABS; | ||
1546 | new_block_exp = GNUNET_TIME_UNIT_ZERO_ABS; | ||
1547 | name_len = ntohs (rd_set->name_len); | ||
1548 | *len += name_len; | ||
1549 | rd_count = ntohs (rd_set->rd_count); | ||
1550 | rd_ser_len = ntohs (rd_set->rd_len); | ||
1551 | *len += rd_ser_len; | ||
1552 | name_tmp = (const char *) &rd_set[1]; | ||
1553 | rd_ser = &name_tmp[name_len]; | ||
1554 | { | ||
1555 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; | ||
1556 | |||
1557 | /* Extracting and converting private key */ | ||
1558 | conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp); | ||
1559 | if (NULL == conv_name) | ||
1560 | { | ||
1561 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1562 | "Error normalizing name `%s'\n", | ||
1563 | name_tmp); | ||
1564 | return GNUNET_EC_NAMESTORE_LABEL_INVALID; | ||
1565 | } | ||
1566 | |||
1567 | /* Check name for validity */ | ||
1568 | if (GNUNET_OK != GNUNET_GNSRECORD_label_check (conv_name, &emsg)) | ||
1569 | { | ||
1570 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1571 | "Label invalid: `%s'\n", | ||
1572 | emsg); | ||
1573 | GNUNET_free (emsg); | ||
1574 | GNUNET_free (conv_name); | ||
1575 | return GNUNET_EC_NAMESTORE_LABEL_INVALID; | ||
1576 | } | ||
1577 | |||
1578 | if (GNUNET_OK != | ||
1579 | GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, | ||
1580 | rd)) | ||
1581 | { | ||
1582 | GNUNET_free (conv_name); | ||
1583 | return GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID; | ||
1584 | } | ||
1585 | |||
1586 | GNUNET_STATISTICS_update (statistics, | ||
1587 | "Well-formed store requests received", | ||
1588 | 1, | ||
1589 | GNUNET_NO); | ||
1590 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1591 | "Creating %u records for name `%s'\n", | ||
1592 | (unsigned int) rd_count, | ||
1593 | conv_name); | ||
1594 | if ((GNUNET_NO == nc->GSN_database->lookup_records (nc->GSN_database->cls, | ||
1595 | private_key, | ||
1596 | conv_name, | ||
1597 | &get_existing_rd_exp, | ||
1598 | &lctx)) | ||
1599 | && | ||
1600 | (rd_count == 0)) | ||
1601 | { | ||
1602 | /* This name does not exist, so cannot be removed */ | ||
1603 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1604 | "Name `%s' does not exist, no deletion required\n", | ||
1605 | conv_name); | ||
1606 | res = GNUNET_NO; | ||
1607 | ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND; | ||
1608 | } | ||
1609 | else | ||
1610 | { | ||
1611 | /* remove "NICK" records, unless this is for the | ||
1612 | #GNUNET_GNS_EMPTY_LABEL_AT label | ||
1613 | We may need one additional record later for tombstone. | ||
1614 | FIXME: Since we must normalize the record set (check for | ||
1615 | consistency etc) we have to iterate the set twice. | ||
1616 | May be inefficient. | ||
1617 | We cannot really move the nick caching into GNSRECORD. | ||
1618 | */ | ||
1619 | struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count)]; | ||
1620 | struct GNUNET_GNSRECORD_Data rd_nf[GNUNET_NZL (rd_count) + 1]; | ||
1621 | unsigned int rd_clean_off; | ||
1622 | unsigned int rd_nf_count; | ||
1623 | int have_nick; | ||
1624 | |||
1625 | rd_clean_off = 0; | ||
1626 | have_nick = GNUNET_NO; | ||
1627 | for (unsigned int i = 0; i < rd_count; i++) | ||
1628 | { | ||
1629 | rd_clean[rd_clean_off] = rd[i]; | ||
1630 | |||
1631 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) || | ||
1632 | (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type)) | ||
1633 | rd_clean_off++; | ||
1634 | |||
1635 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && | ||
1636 | (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type)) | ||
1637 | { | ||
1638 | // FIXME: In case this is an uncommited transaction, | ||
1639 | // we should not do this here. Can we do this in the store activity? | ||
1640 | cache_nick (private_key, &rd[i]); | ||
1641 | have_nick = GNUNET_YES; | ||
1642 | } | ||
1643 | } | ||
1644 | if (GNUNET_OK != | ||
1645 | GNUNET_GNSRECORD_normalize_record_set (conv_name, | ||
1646 | rd_clean, | ||
1647 | rd_clean_off, | ||
1648 | rd_nf, | ||
1649 | &rd_nf_count, | ||
1650 | &new_block_exp, | ||
1651 | GNUNET_GNSRECORD_FILTER_NONE, | ||
1652 | &emsg)) | ||
1653 | { | ||
1654 | GNUNET_free (conv_name); | ||
1655 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1656 | "Error normalizing record set: `%s'\n", | ||
1657 | emsg); | ||
1658 | GNUNET_free (emsg); | ||
1659 | return GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID; | ||
1660 | } | ||
1661 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1662 | "%u/%u records before tombstone\n", rd_nf_count, | ||
1663 | rd_clean_off); | ||
1664 | /* | ||
1665 | * If existing_block_exp is 0, then there was no record set | ||
1666 | * and no tombstone. | ||
1667 | * Otherwise, if the existing block expiration is after the | ||
1668 | * new block expiration would be, we need to add a tombstone | ||
1669 | * or update it. | ||
1670 | */ | ||
1671 | if (GNUNET_TIME_absolute_cmp (new_block_exp, <=, lctx.exp)) | ||
1672 | { | ||
1673 | rd_nf[rd_nf_count].record_type = GNUNET_GNSRECORD_TYPE_TOMBSTONE; | ||
1674 | rd_nf[rd_nf_count].expiration_time = | ||
1675 | lctx.exp.abs_value_us; | ||
1676 | rd_nf[rd_nf_count].data = NULL; | ||
1677 | rd_nf[rd_nf_count].data_size = 0; | ||
1678 | rd_nf[rd_nf_count].flags = GNUNET_GNSRECORD_RF_PRIVATE; | ||
1679 | rd_nf_count++; | ||
1680 | } | ||
1681 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && | ||
1682 | (GNUNET_NO == have_nick)) | ||
1683 | { | ||
1684 | /* remove nick record from cache, in case we have one there */ | ||
1685 | // FIXME: In case this is an uncommited transaction, | ||
1686 | // we should not do this here. Can we do this in the store activity? | ||
1687 | cache_nick (private_key, NULL); | ||
1688 | } | ||
1689 | res = nc->GSN_database->store_records (nc->GSN_database->cls, | ||
1690 | private_key, | ||
1691 | conv_name, | ||
1692 | rd_nf_count, | ||
1693 | rd_nf); | ||
1694 | /* If after a store there is only a TOMBSTONE left, and | ||
1695 | * there was >1 record under this label found (the tombstone; indicated | ||
1696 | * through res != GNUNET_NO) then we should return "NOT FOUND" == GNUNET_NO | ||
1697 | */ | ||
1698 | if ((GNUNET_SYSERR != res) && | ||
1699 | (0 == rd_count) && | ||
1700 | (1 == rd_nf_count) && | ||
1701 | (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd_nf[0].record_type) && | ||
1702 | (GNUNET_YES == lctx.only_tombstone)) | ||
1703 | { | ||
1704 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1705 | "Client tried to remove non-existant record\n"); | ||
1706 | ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND; | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | if (GNUNET_SYSERR == res) | ||
1711 | { | ||
1712 | /* store not successful, no need to tell monitors */ | ||
1713 | GNUNET_free (conv_name); | ||
1714 | return GNUNET_EC_NAMESTORE_STORE_FAILED; | ||
1715 | } | ||
1716 | } | ||
1717 | GNUNET_free (conv_name); | ||
1718 | return ec; | ||
1719 | } | ||
1720 | |||
1721 | /** | ||
1722 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message | ||
1723 | * | ||
1724 | * @param cls client sending the message | ||
1725 | * @param rp_msg message of type `struct RecordStoreMessage` | ||
1726 | */ | ||
1727 | static void | ||
1728 | handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | ||
1729 | { | ||
1730 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
1731 | struct NamestoreClient *nc = cls; | ||
1732 | uint32_t rid; | ||
1733 | uint16_t rd_set_count; | ||
1734 | const char *buf; | ||
1735 | ssize_t read; | ||
1736 | size_t key_len; | ||
1737 | size_t kb_read; | ||
1738 | size_t rp_msg_len; | ||
1739 | size_t rs_len; | ||
1740 | size_t rs_off; | ||
1741 | struct StoreActivity *sa; | ||
1742 | struct RecordSet *rs; | ||
1743 | enum GNUNET_ErrorCode res; | ||
1744 | |||
1745 | key_len = ntohs (rp_msg->key_len); | ||
1746 | rp_msg_len = ntohs (rp_msg->gns_header.header.size); | ||
1747 | rs_off = sizeof (*rp_msg) + key_len; | ||
1748 | rs_len = rp_msg_len - rs_off; | ||
1749 | if ((GNUNET_SYSERR == | ||
1750 | GNUNET_CRYPTO_read_private_key_from_buffer (&rp_msg[1], | ||
1751 | key_len, | ||
1752 | &zone, | ||
1753 | &kb_read)) || | ||
1754 | (kb_read != key_len)) | ||
1755 | { | ||
1756 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1757 | "Error reading private key\n"); | ||
1758 | GNUNET_SERVICE_client_drop (nc->client); | ||
1759 | return; | ||
1760 | } | ||
1761 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1762 | "Received NAMESTORE_RECORD_STORE message\n"); | ||
1763 | rid = ntohl (rp_msg->gns_header.r_id); | ||
1764 | rd_set_count = ntohs (rp_msg->rd_set_count); | ||
1765 | buf = (const char *) rp_msg + rs_off; | ||
1766 | for (int i = 0; i < rd_set_count; i++) | ||
1767 | { | ||
1768 | rs = (struct RecordSet *) buf; | ||
1769 | res = store_record_set (nc, &zone, | ||
1770 | rs, &read); | ||
1771 | if (GNUNET_EC_NONE != res) | ||
1772 | { | ||
1773 | send_store_response (nc, res, rid); | ||
1774 | GNUNET_SERVICE_client_continue (nc->client); | ||
1775 | return; | ||
1776 | } | ||
1777 | buf += read; | ||
1778 | } | ||
1779 | sa = GNUNET_malloc (sizeof(struct StoreActivity) + rs_len); | ||
1780 | GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa); | ||
1781 | sa->nc = nc; | ||
1782 | sa->rs = (struct RecordSet *) &sa[1]; | ||
1783 | sa->rd_set_count = rd_set_count; | ||
1784 | GNUNET_memcpy (&sa[1], (char *) rp_msg + rs_off, rs_len); | ||
1785 | sa->rid = rid; | ||
1786 | sa->rd_set_pos = 0; | ||
1787 | sa->private_key = zone; | ||
1788 | sa->zm_pos = monitor_head; | ||
1789 | sa->uncommited = nc->in_transaction; | ||
1790 | continue_store_activity (sa, GNUNET_YES); | ||
1791 | } | ||
1792 | |||
1793 | static void | ||
1794 | send_tx_response (int rid, enum GNUNET_ErrorCode ec, struct NamestoreClient *nc) | ||
1795 | { | ||
1796 | struct TxControlResultMessage *txr_msg; | ||
1797 | struct GNUNET_MQ_Envelope *env; | ||
1798 | |||
1799 | env = | ||
1800 | GNUNET_MQ_msg (txr_msg, GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL_RESULT); | ||
1801 | txr_msg->gns_header.r_id = rid; | ||
1802 | txr_msg->ec = htonl (ec); | ||
1803 | GNUNET_MQ_send (nc->mq, env); | ||
1804 | } | ||
1805 | |||
1806 | /** | ||
1807 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL message | ||
1808 | * | ||
1809 | * @param cls client sending the message | ||
1810 | * @param tx_msg message of type `struct TxControlMessage` | ||
1811 | */ | ||
1812 | static void | ||
1813 | handle_tx_control (void *cls, const struct TxControlMessage *tx_msg) | ||
1814 | { | ||
1815 | struct NamestoreClient *nc = cls; | ||
1816 | struct StoreActivity *sa = sa_head; | ||
1817 | struct StoreActivity *sn; | ||
1818 | enum GNUNET_GenericReturnValue ret; | ||
1819 | char *emsg = NULL; | ||
1820 | int blocked = GNUNET_NO; | ||
1821 | |||
1822 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received TX_CONTROL message\n"); | ||
1823 | |||
1824 | switch (ntohs (tx_msg->control)) | ||
1825 | { | ||
1826 | case GNUNET_NAMESTORE_TX_BEGIN: | ||
1827 | ret = nc->GSN_database->transaction_begin (nc->GSN_database->cls, | ||
1828 | &emsg); | ||
1829 | send_tx_response (tx_msg->gns_header.r_id, | ||
1830 | (GNUNET_SYSERR == ret) ? | ||
1831 | GNUNET_EC_NAMESTORE_BACKEND_FAILED : GNUNET_EC_NONE, nc); | ||
1832 | if (GNUNET_SYSERR == ret) | ||
1833 | { | ||
1834 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1835 | "Databse backend error: `%s'", emsg); | ||
1836 | GNUNET_free (emsg); | ||
1837 | } | ||
1838 | GNUNET_SERVICE_client_continue (nc->client); | ||
1839 | nc->in_transaction = GNUNET_YES; | ||
1840 | break; | ||
1841 | case GNUNET_NAMESTORE_TX_COMMIT: | ||
1842 | ret = nc->GSN_database->transaction_commit (nc->GSN_database->cls, | ||
1843 | &emsg); | ||
1844 | send_tx_response (tx_msg->gns_header.r_id, | ||
1845 | (GNUNET_SYSERR == ret) ? | ||
1846 | GNUNET_EC_NAMESTORE_BACKEND_FAILED : GNUNET_EC_NONE, | ||
1847 | nc); | ||
1848 | if (GNUNET_SYSERR == ret) | ||
1849 | { | ||
1850 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1851 | "Databse backend error: `%s'", emsg); | ||
1852 | GNUNET_free (emsg); | ||
1853 | } | ||
1854 | if (GNUNET_SYSERR != ret) | ||
1855 | { | ||
1856 | nc->in_transaction = GNUNET_NO; | ||
1857 | while (NULL != sa) | ||
1858 | { | ||
1859 | if ((nc != sa->nc) || | ||
1860 | (GNUNET_NO == sa->uncommited)) | ||
1861 | { | ||
1862 | sa = sa->next; | ||
1863 | continue; | ||
1864 | } | ||
1865 | sa->uncommited = GNUNET_NO; | ||
1866 | sn = sa->next; | ||
1867 | if (GNUNET_OK != continue_store_activity (sa, GNUNET_NO)) | ||
1868 | blocked = GNUNET_YES; | ||
1869 | sa = sn; | ||
1870 | } | ||
1871 | if (GNUNET_YES != blocked) | ||
1872 | GNUNET_SERVICE_client_continue (nc->client); | ||
1873 | } | ||
1874 | break; | ||
1875 | case GNUNET_NAMESTORE_TX_ROLLBACK: | ||
1876 | ret = nc->GSN_database->transaction_rollback (nc->GSN_database->cls, | ||
1877 | &emsg); | ||
1878 | send_tx_response (tx_msg->gns_header.r_id, | ||
1879 | (GNUNET_SYSERR == ret) ? | ||
1880 | GNUNET_EC_NAMESTORE_BACKEND_FAILED : GNUNET_EC_NONE, nc); | ||
1881 | GNUNET_SERVICE_client_continue (nc->client); | ||
1882 | if (GNUNET_SYSERR == ret) | ||
1883 | { | ||
1884 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1885 | "Databse backend error: `%s'", emsg); | ||
1886 | GNUNET_free (emsg); | ||
1887 | } | ||
1888 | if (GNUNET_SYSERR != ret) | ||
1889 | { | ||
1890 | nc->in_transaction = GNUNET_NO; | ||
1891 | while (NULL != sa) | ||
1892 | { | ||
1893 | if ((nc != sa->nc) || | ||
1894 | (GNUNET_NO == sa->uncommited)) | ||
1895 | { | ||
1896 | sa = sa->next; | ||
1897 | continue; | ||
1898 | } | ||
1899 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1900 | "Discarding uncommited StoreActivity\n"); | ||
1901 | sn = sa->next; | ||
1902 | free_store_activity (sa); | ||
1903 | sa = sn; | ||
1904 | } | ||
1905 | } | ||
1906 | break; | ||
1907 | default: | ||
1908 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1909 | "Unknown control type %u\n", ntohs (tx_msg->control)); | ||
1910 | GNUNET_break (0); | ||
1911 | } | ||
1912 | } | ||
1913 | |||
1914 | /** | ||
1915 | * Context for record remove operations passed from #handle_zone_to_name to | ||
1916 | * #handle_zone_to_name_it as closure | ||
1917 | */ | ||
1918 | struct ZoneToNameCtx | ||
1919 | { | ||
1920 | /** | ||
1921 | * Namestore client | ||
1922 | */ | ||
1923 | struct NamestoreClient *nc; | ||
1924 | |||
1925 | /** | ||
1926 | * Request id (to be used in the response to the client). | ||
1927 | */ | ||
1928 | uint32_t rid; | ||
1929 | |||
1930 | /** | ||
1931 | * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error. Note that | ||
1932 | * not finding a name for the zone still counts as a 'success' here, | ||
1933 | * as this field is about the success of executing the IPC protocol. | ||
1934 | */ | ||
1935 | enum GNUNET_ErrorCode ec; | ||
1936 | }; | ||
1937 | |||
1938 | |||
1939 | /** | ||
1940 | * Zone to name iterator | ||
1941 | * | ||
1942 | * @param cls struct ZoneToNameCtx * | ||
1943 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
1944 | * @param zone_key the zone key | ||
1945 | * @param name name | ||
1946 | * @param rd_count number of records in @a rd | ||
1947 | * @param rd record data | ||
1948 | */ | ||
1949 | static void | ||
1950 | handle_zone_to_name_it (void *cls, | ||
1951 | uint64_t seq, | ||
1952 | const struct GNUNET_CRYPTO_PrivateKey *zone_key, | ||
1953 | const char *name, | ||
1954 | unsigned int rd_count, | ||
1955 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1956 | { | ||
1957 | struct ZoneToNameCtx *ztn_ctx = cls; | ||
1958 | struct GNUNET_MQ_Envelope *env; | ||
1959 | struct ZoneToNameResponseMessage *ztnr_msg; | ||
1960 | size_t name_len; | ||
1961 | size_t key_len; | ||
1962 | ssize_t rd_ser_len; | ||
1963 | size_t msg_size; | ||
1964 | char *name_tmp; | ||
1965 | char *rd_tmp; | ||
1966 | |||
1967 | GNUNET_assert (0 != seq); | ||
1968 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1969 | "Found result for zone-to-name lookup: `%s'\n", | ||
1970 | name); | ||
1971 | ztn_ctx->ec = GNUNET_EC_NONE; | ||
1972 | name_len = (NULL == name) ? 0 : strlen (name) + 1; | ||
1973 | rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | ||
1974 | if (rd_ser_len < 0) | ||
1975 | { | ||
1976 | GNUNET_break (0); | ||
1977 | ztn_ctx->ec = htonl (GNUNET_EC_NAMESTORE_UNKNOWN); | ||
1978 | return; | ||
1979 | } | ||
1980 | key_len = GNUNET_CRYPTO_private_key_get_length (zone_key); | ||
1981 | msg_size = sizeof(struct ZoneToNameResponseMessage) | ||
1982 | + name_len + rd_ser_len + key_len; | ||
1983 | if (msg_size >= GNUNET_MAX_MESSAGE_SIZE) | ||
1984 | { | ||
1985 | GNUNET_break (0); | ||
1986 | ztn_ctx->ec = GNUNET_EC_NAMESTORE_RECORD_TOO_BIG; | ||
1987 | return; | ||
1988 | } | ||
1989 | env = | ||
1990 | GNUNET_MQ_msg_extra (ztnr_msg, | ||
1991 | key_len + name_len + rd_ser_len, | ||
1992 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE); | ||
1993 | ztnr_msg->gns_header.header.size = htons (msg_size); | ||
1994 | ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid); | ||
1995 | ztnr_msg->ec = htonl (ztn_ctx->ec); | ||
1996 | ztnr_msg->rd_len = htons (rd_ser_len); | ||
1997 | ztnr_msg->rd_count = htons (rd_count); | ||
1998 | ztnr_msg->name_len = htons (name_len); | ||
1999 | ztnr_msg->key_len = htons (key_len); | ||
2000 | GNUNET_CRYPTO_write_private_key_to_buffer (zone_key, | ||
2001 | &ztnr_msg[1], | ||
2002 | key_len); | ||
2003 | name_tmp = (char *) &ztnr_msg[1] + key_len; | ||
2004 | GNUNET_memcpy (name_tmp, name, name_len); | ||
2005 | rd_tmp = &name_tmp[name_len]; | ||
2006 | GNUNET_assert ( | ||
2007 | rd_ser_len == | ||
2008 | GNUNET_GNSRECORD_records_serialize (rd_count, rd, rd_ser_len, rd_tmp)); | ||
2009 | ztn_ctx->ec = GNUNET_EC_NONE; | ||
2010 | GNUNET_MQ_send (ztn_ctx->nc->mq, env); | ||
2011 | } | ||
2012 | |||
2013 | static enum GNUNET_GenericReturnValue | ||
2014 | check_zone_to_name (void *cls, | ||
2015 | const struct ZoneToNameMessage *zis_msg) | ||
2016 | { | ||
2017 | return GNUNET_OK; | ||
2018 | } | ||
2019 | |||
2020 | |||
2021 | /** | ||
2022 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message | ||
2023 | * | ||
2024 | * @param cls client client sending the message | ||
2025 | * @param ztn_msg message of type 'struct ZoneToNameMessage' | ||
2026 | */ | ||
2027 | static void | ||
2028 | handle_zone_to_name (void *cls, const struct ZoneToNameMessage *ztn_msg) | ||
2029 | { | ||
2030 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
2031 | struct GNUNET_CRYPTO_PublicKey value_zone; | ||
2032 | struct NamestoreClient *nc = cls; | ||
2033 | struct ZoneToNameCtx ztn_ctx; | ||
2034 | struct GNUNET_MQ_Envelope *env; | ||
2035 | struct ZoneToNameResponseMessage *ztnr_msg; | ||
2036 | size_t key_len; | ||
2037 | size_t pkey_len; | ||
2038 | size_t kb_read; | ||
2039 | |||
2040 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ZONE_TO_NAME message\n"); | ||
2041 | ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id); | ||
2042 | ztn_ctx.nc = nc; | ||
2043 | ztn_ctx.ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND; | ||
2044 | key_len = ntohs (ztn_msg->key_len); | ||
2045 | if ((GNUNET_SYSERR == | ||
2046 | GNUNET_CRYPTO_read_private_key_from_buffer (&ztn_msg[1], | ||
2047 | key_len, | ||
2048 | &zone, | ||
2049 | &kb_read)) || | ||
2050 | (kb_read != key_len)) | ||
2051 | { | ||
2052 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2053 | "Error parsing private key.\n"); | ||
2054 | GNUNET_SERVICE_client_drop (nc->client); | ||
2055 | GNUNET_break (0); | ||
2056 | return; | ||
2057 | } | ||
2058 | pkey_len = ntohs (ztn_msg->pkey_len); | ||
2059 | if ((GNUNET_SYSERR == | ||
2060 | GNUNET_CRYPTO_read_public_key_from_buffer ((char*) &ztn_msg[1] | ||
2061 | + key_len, | ||
2062 | pkey_len, | ||
2063 | &value_zone, | ||
2064 | &kb_read)) || | ||
2065 | (kb_read != pkey_len)) | ||
2066 | { | ||
2067 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2068 | "Error parsing public key.\n"); | ||
2069 | GNUNET_SERVICE_client_drop (nc->client); | ||
2070 | GNUNET_break (0); | ||
2071 | return; | ||
2072 | } | ||
2073 | if (GNUNET_SYSERR == nc->GSN_database->zone_to_name (nc->GSN_database->cls, | ||
2074 | &zone, | ||
2075 | &value_zone, | ||
2076 | &handle_zone_to_name_it, | ||
2077 | &ztn_ctx)) | ||
2078 | { | ||
2079 | /* internal error, hang up instead of signalling something | ||
2080 | that might be wrong */ | ||
2081 | GNUNET_break (0); | ||
2082 | GNUNET_SERVICE_client_drop (nc->client); | ||
2083 | return; | ||
2084 | } | ||
2085 | if (GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND == ztn_ctx.ec) | ||
2086 | { | ||
2087 | /* no result found, send empty response */ | ||
2088 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2089 | "Found no result for zone-to-name lookup.\n"); | ||
2090 | env = GNUNET_MQ_msg (ztnr_msg, | ||
2091 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE); | ||
2092 | ztnr_msg->gns_header.r_id = ztn_msg->gns_header.r_id; | ||
2093 | ztnr_msg->ec = htonl (GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND); | ||
2094 | GNUNET_MQ_send (nc->mq, env); | ||
2095 | } | ||
2096 | GNUNET_SERVICE_client_continue (nc->client); | ||
2097 | } | ||
2098 | |||
2099 | |||
2100 | /** | ||
2101 | * Context for record remove operations passed from | ||
2102 | * #run_zone_iteration_round to #zone_iterate_proc as closure | ||
2103 | */ | ||
2104 | struct ZoneIterationProcResult | ||
2105 | { | ||
2106 | /** | ||
2107 | * The zone iteration handle | ||
2108 | */ | ||
2109 | struct ZoneIteration *zi; | ||
2110 | |||
2111 | /** | ||
2112 | * Number of results left to be returned in this iteration. | ||
2113 | */ | ||
2114 | uint64_t limit; | ||
2115 | |||
2116 | /** | ||
2117 | * Skip a result and run again unless GNUNET_NO | ||
2118 | */ | ||
2119 | int run_again; | ||
2120 | }; | ||
2121 | |||
2122 | |||
2123 | /** | ||
2124 | * Process results for zone iteration from database | ||
2125 | * | ||
2126 | * @param cls struct ZoneIterationProcResult | ||
2127 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
2128 | * @param zone_key the zone key | ||
2129 | * @param name name | ||
2130 | * @param rd_count number of records for this name | ||
2131 | * @param rd record data | ||
2132 | */ | ||
2133 | static void | ||
2134 | zone_iterate_proc (void *cls, | ||
2135 | uint64_t seq, | ||
2136 | const struct GNUNET_CRYPTO_PrivateKey *zone_key, | ||
2137 | const char *name, | ||
2138 | unsigned int rd_count, | ||
2139 | const struct GNUNET_GNSRECORD_Data *rd) | ||
2140 | { | ||
2141 | struct ZoneIterationProcResult *proc = cls; | ||
2142 | |||
2143 | GNUNET_assert (0 != seq); | ||
2144 | if ((NULL == zone_key) && (NULL == name)) | ||
2145 | { | ||
2146 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n"); | ||
2147 | return; | ||
2148 | } | ||
2149 | if ((NULL == zone_key) || (NULL == name)) | ||
2150 | { | ||
2151 | /* what is this!? should never happen */ | ||
2152 | GNUNET_break (0); | ||
2153 | return; | ||
2154 | } | ||
2155 | if (0 == proc->limit) | ||
2156 | { | ||
2157 | /* what is this!? should never happen */ | ||
2158 | GNUNET_break (0); | ||
2159 | return; | ||
2160 | } | ||
2161 | proc->zi->seq = seq; | ||
2162 | if (0 < send_lookup_response_with_filter (proc->zi->nc, | ||
2163 | proc->zi->request_id, | ||
2164 | zone_key, | ||
2165 | name, | ||
2166 | rd_count, | ||
2167 | rd, | ||
2168 | proc->zi->filter)) | ||
2169 | proc->limit--; | ||
2170 | else | ||
2171 | proc->run_again = GNUNET_YES; | ||
2172 | } | ||
2173 | |||
2174 | |||
2175 | /** | ||
2176 | * Perform the next round of the zone iteration. | ||
2177 | * | ||
2178 | * @param zi zone iterator to process | ||
2179 | * @param limit number of results to return in one pass | ||
2180 | */ | ||
2181 | static void | ||
2182 | run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit) | ||
2183 | { | ||
2184 | struct ZoneIterationProcResult proc; | ||
2185 | struct GNUNET_TIME_Absolute start; | ||
2186 | struct GNUNET_TIME_Relative duration; | ||
2187 | struct NamestoreClient *nc = zi->nc; | ||
2188 | |||
2189 | memset (&proc, 0, sizeof(proc)); | ||
2190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2191 | "Asked to return up to %llu records at position %llu\n", | ||
2192 | (unsigned long long) limit, | ||
2193 | (unsigned long long) zi->seq); | ||
2194 | proc.zi = zi; | ||
2195 | proc.limit = limit; | ||
2196 | proc.run_again = GNUNET_YES; | ||
2197 | start = GNUNET_TIME_absolute_get (); | ||
2198 | while (GNUNET_YES == proc.run_again) | ||
2199 | { | ||
2200 | proc.run_again = GNUNET_NO; | ||
2201 | GNUNET_break (GNUNET_SYSERR != | ||
2202 | nc->GSN_database->iterate_records (nc->GSN_database->cls, | ||
2203 | (GNUNET_YES == | ||
2204 | GNUNET_is_zero ( | ||
2205 | &zi->zone)) | ||
2206 | ? NULL | ||
2207 | : &zi->zone, | ||
2208 | zi->seq, | ||
2209 | proc.limit, | ||
2210 | &zone_iterate_proc, | ||
2211 | &proc)); | ||
2212 | } | ||
2213 | duration = GNUNET_TIME_absolute_get_duration (start); | ||
2214 | duration = GNUNET_TIME_relative_divide (duration, limit - proc.limit); | ||
2215 | GNUNET_STATISTICS_set (statistics, | ||
2216 | "NAMESTORE iteration delay (μs/record)", | ||
2217 | duration.rel_value_us, | ||
2218 | GNUNET_NO); | ||
2219 | if (0 == proc.limit) | ||
2220 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2221 | "Returned %llu results, more results available\n", | ||
2222 | (unsigned long long) limit); | ||
2223 | zi->send_end = (0 != proc.limit); | ||
2224 | if (0 == zi->cache_ops) | ||
2225 | zone_iteration_done_client_continue (zi); | ||
2226 | } | ||
2227 | |||
2228 | static enum GNUNET_GenericReturnValue | ||
2229 | check_iteration_start (void *cls, | ||
2230 | const struct ZoneIterationStartMessage *zis_msg) | ||
2231 | { | ||
2232 | uint16_t size; | ||
2233 | size_t key_len; | ||
2234 | |||
2235 | size = ntohs (zis_msg->gns_header.header.size); | ||
2236 | key_len = ntohs (zis_msg->key_len); | ||
2237 | |||
2238 | if (size < key_len + sizeof(*zis_msg)) | ||
2239 | { | ||
2240 | GNUNET_break (0); | ||
2241 | return GNUNET_SYSERR; | ||
2242 | } | ||
2243 | return GNUNET_OK; | ||
2244 | } | ||
2245 | |||
2246 | |||
2247 | /** | ||
2248 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message | ||
2249 | * | ||
2250 | * @param cls the client sending the message | ||
2251 | * @param zis_msg message from the client | ||
2252 | */ | ||
2253 | static void | ||
2254 | handle_iteration_start (void *cls, | ||
2255 | const struct ZoneIterationStartMessage *zis_msg) | ||
2256 | { | ||
2257 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
2258 | struct NamestoreClient *nc = cls; | ||
2259 | struct ZoneIteration *zi; | ||
2260 | size_t key_len; | ||
2261 | size_t kb_read; | ||
2262 | |||
2263 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2264 | "Received ZONE_ITERATION_START message\n"); | ||
2265 | key_len = ntohs (zis_msg->key_len); | ||
2266 | zi = GNUNET_new (struct ZoneIteration); | ||
2267 | if (0 < key_len) | ||
2268 | { | ||
2269 | if ((GNUNET_SYSERR == | ||
2270 | GNUNET_CRYPTO_read_private_key_from_buffer (&zis_msg[1], | ||
2271 | key_len, | ||
2272 | &zone, | ||
2273 | &kb_read)) || | ||
2274 | (kb_read != key_len)) | ||
2275 | { | ||
2276 | GNUNET_SERVICE_client_drop (nc->client); | ||
2277 | GNUNET_free (zi); | ||
2278 | return; | ||
2279 | } | ||
2280 | zi->zone = zone; | ||
2281 | } | ||
2282 | zi->request_id = ntohl (zis_msg->gns_header.r_id); | ||
2283 | zi->filter = ntohs (zis_msg->filter); | ||
2284 | zi->offset = 0; | ||
2285 | zi->nc = nc; | ||
2286 | GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi); | ||
2287 | run_zone_iteration_round (zi, 1); | ||
2288 | } | ||
2289 | |||
2290 | |||
2291 | /** | ||
2292 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message | ||
2293 | * | ||
2294 | * @param cls the client sending the message | ||
2295 | * @param zis_msg message from the client | ||
2296 | */ | ||
2297 | static void | ||
2298 | handle_iteration_stop (void *cls, | ||
2299 | const struct ZoneIterationStopMessage *zis_msg) | ||
2300 | { | ||
2301 | struct NamestoreClient *nc = cls; | ||
2302 | struct ZoneIteration *zi; | ||
2303 | uint32_t rid; | ||
2304 | |||
2305 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2306 | "Received ZONE_ITERATION_STOP message\n"); | ||
2307 | rid = ntohl (zis_msg->gns_header.r_id); | ||
2308 | for (zi = nc->op_head; NULL != zi; zi = zi->next) | ||
2309 | if (zi->request_id == rid) | ||
2310 | break; | ||
2311 | if (NULL == zi) | ||
2312 | { | ||
2313 | GNUNET_break (0); | ||
2314 | GNUNET_SERVICE_client_drop (nc->client); | ||
2315 | return; | ||
2316 | } | ||
2317 | GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi); | ||
2318 | GNUNET_free (zi); | ||
2319 | GNUNET_SERVICE_client_continue (nc->client); | ||
2320 | } | ||
2321 | |||
2322 | |||
2323 | /** | ||
2324 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message | ||
2325 | * | ||
2326 | * @param cls the client sending the message | ||
2327 | * @param zis_msg message from the client | ||
2328 | */ | ||
2329 | static void | ||
2330 | handle_iteration_next (void *cls, | ||
2331 | const struct ZoneIterationNextMessage *zis_msg) | ||
2332 | { | ||
2333 | struct NamestoreClient *nc = cls; | ||
2334 | struct ZoneIteration *zi; | ||
2335 | uint32_t rid; | ||
2336 | uint64_t limit; | ||
2337 | |||
2338 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2339 | "Received ZONE_ITERATION_NEXT message\n"); | ||
2340 | GNUNET_STATISTICS_update (statistics, | ||
2341 | "Iteration NEXT messages received", | ||
2342 | 1, | ||
2343 | GNUNET_NO); | ||
2344 | rid = ntohl (zis_msg->gns_header.r_id); | ||
2345 | limit = GNUNET_ntohll (zis_msg->limit); | ||
2346 | for (zi = nc->op_head; NULL != zi; zi = zi->next) | ||
2347 | if (zi->request_id == rid) | ||
2348 | break; | ||
2349 | if (NULL == zi) | ||
2350 | { | ||
2351 | GNUNET_break (0); | ||
2352 | GNUNET_SERVICE_client_drop (nc->client); | ||
2353 | return; | ||
2354 | } | ||
2355 | run_zone_iteration_round (zi, limit); | ||
2356 | } | ||
2357 | |||
2358 | |||
2359 | /** | ||
2360 | * Function called when the monitor is ready for more data, and we | ||
2361 | * should thus unblock PUT operations that were blocked on the | ||
2362 | * monitor not being ready. | ||
2363 | */ | ||
2364 | static void | ||
2365 | monitor_unblock (struct ZoneMonitor *zm) | ||
2366 | { | ||
2367 | struct StoreActivity *sa = sa_head; | ||
2368 | |||
2369 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2370 | "Unblocking zone monitor %p\n", zm); | ||
2371 | while ((NULL != sa) && (zm->limit > zm->iteration_cnt)) | ||
2372 | { | ||
2373 | struct StoreActivity *sn = sa->next; | ||
2374 | |||
2375 | if (sa->zm_pos == zm) | ||
2376 | continue_store_activity (sa, GNUNET_YES); | ||
2377 | sa = sn; | ||
2378 | } | ||
2379 | if (zm->limit > zm->iteration_cnt) | ||
2380 | { | ||
2381 | zm->sa_waiting = GNUNET_NO; | ||
2382 | if (NULL != zm->sa_wait_warning) | ||
2383 | { | ||
2384 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
2385 | zm->sa_wait_warning = NULL; | ||
2386 | } | ||
2387 | } | ||
2388 | else if (GNUNET_YES == zm->sa_waiting) | ||
2389 | { | ||
2390 | zm->sa_waiting_start = GNUNET_TIME_absolute_get (); | ||
2391 | if (NULL != zm->sa_wait_warning) | ||
2392 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
2393 | zm->sa_wait_warning = | ||
2394 | GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
2395 | &warn_monitor_slow, | ||
2396 | zm); | ||
2397 | } | ||
2398 | } | ||
2399 | |||
2400 | |||
2401 | /** | ||
2402 | * Send 'sync' message to zone monitor, we're now in sync. | ||
2403 | * | ||
2404 | * @param zm monitor that is now in sync | ||
2405 | */ | ||
2406 | static void | ||
2407 | monitor_sync (struct ZoneMonitor *zm) | ||
2408 | { | ||
2409 | struct GNUNET_MQ_Envelope *env; | ||
2410 | struct GNUNET_MessageHeader *sync; | ||
2411 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2412 | "Synching zone monitor %p\n", zm); | ||
2413 | |||
2414 | env = GNUNET_MQ_msg (sync, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC); | ||
2415 | GNUNET_MQ_send (zm->nc->mq, env); | ||
2416 | /* mark iteration done */ | ||
2417 | zm->in_first_iteration = GNUNET_NO; | ||
2418 | zm->iteration_cnt = 0; | ||
2419 | if ((zm->limit > 0) && (zm->sa_waiting)) | ||
2420 | monitor_unblock (zm); | ||
2421 | } | ||
2422 | |||
2423 | |||
2424 | /** | ||
2425 | * Obtain the next datum during the zone monitor's zone initial iteration. | ||
2426 | * | ||
2427 | * @param cls zone monitor that does its initial iteration | ||
2428 | */ | ||
2429 | static void | ||
2430 | monitor_iteration_next (void *cls); | ||
2431 | |||
2432 | |||
2433 | /** | ||
2434 | * A #GNUNET_NAMESTORE_RecordIterator for monitors. | ||
2435 | * | ||
2436 | * @param cls a 'struct ZoneMonitor *' with information about the monitor | ||
2437 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
2438 | * @param zone_key zone key of the zone | ||
2439 | * @param name name | ||
2440 | * @param rd_count number of records in @a rd | ||
2441 | * @param rd array of records | ||
2442 | */ | ||
2443 | static void | ||
2444 | monitor_iterate_cb (void *cls, | ||
2445 | uint64_t seq, | ||
2446 | const struct GNUNET_CRYPTO_PrivateKey *zone_key, | ||
2447 | const char *name, | ||
2448 | unsigned int rd_count, | ||
2449 | const struct GNUNET_GNSRECORD_Data *rd) | ||
2450 | { | ||
2451 | struct ZoneMonitor *zm = cls; | ||
2452 | |||
2453 | GNUNET_assert (0 != seq); | ||
2454 | zm->seq = seq; | ||
2455 | GNUNET_assert (NULL != name); | ||
2456 | GNUNET_STATISTICS_update (statistics, | ||
2457 | "Monitor notifications sent", | ||
2458 | 1, | ||
2459 | GNUNET_NO); | ||
2460 | if (0 < send_lookup_response_with_filter (zm->nc, 0, zone_key, name, | ||
2461 | rd_count, rd, zm->filter)) | ||
2462 | { | ||
2463 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2464 | "Sent records.\n"); | ||
2465 | zm->limit--; | ||
2466 | zm->iteration_cnt--; | ||
2467 | } | ||
2468 | else | ||
2469 | zm->run_again = GNUNET_YES; | ||
2470 | if ((0 == zm->iteration_cnt) && (0 != zm->limit)) | ||
2471 | { | ||
2472 | /* We are done with the current iteration batch, AND the | ||
2473 | client would right now accept more, so go again! */ | ||
2474 | GNUNET_assert (NULL == zm->task); | ||
2475 | zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm); | ||
2476 | } | ||
2477 | } | ||
2478 | |||
2479 | static enum GNUNET_GenericReturnValue | ||
2480 | check_monitor_start (void *cls, | ||
2481 | const struct ZoneMonitorStartMessage *zis_msg) | ||
2482 | { | ||
2483 | uint16_t size; | ||
2484 | size_t key_len; | ||
2485 | |||
2486 | size = ntohs (zis_msg->header.size); | ||
2487 | key_len = ntohs (zis_msg->key_len); | ||
2488 | |||
2489 | if (size < key_len + sizeof(*zis_msg)) | ||
2490 | { | ||
2491 | GNUNET_break (0); | ||
2492 | return GNUNET_SYSERR; | ||
2493 | } | ||
2494 | return GNUNET_OK; | ||
2495 | } | ||
2496 | |||
2497 | |||
2498 | /** | ||
2499 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message | ||
2500 | * | ||
2501 | * @param cls the client sending the message | ||
2502 | * @param zis_msg message from the client | ||
2503 | */ | ||
2504 | static void | ||
2505 | handle_monitor_start (void *cls, const struct | ||
2506 | ZoneMonitorStartMessage *zis_msg) | ||
2507 | { | ||
2508 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
2509 | struct NamestoreClient *nc = cls; | ||
2510 | struct ZoneMonitor *zm; | ||
2511 | size_t key_len; | ||
2512 | size_t kb_read; | ||
2513 | |||
2514 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2515 | "Received ZONE_MONITOR_START message\n"); | ||
2516 | zm = GNUNET_new (struct ZoneMonitor); | ||
2517 | zm->nc = nc; | ||
2518 | key_len = ntohs (zis_msg->key_len); | ||
2519 | if (0 < key_len) | ||
2520 | { | ||
2521 | if ((GNUNET_SYSERR == | ||
2522 | GNUNET_CRYPTO_read_private_key_from_buffer (&zis_msg[1], | ||
2523 | key_len, | ||
2524 | &zone, | ||
2525 | &kb_read)) || | ||
2526 | (kb_read != key_len)) | ||
2527 | { | ||
2528 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2529 | "Error reading private key\n"); | ||
2530 | GNUNET_SERVICE_client_drop (nc->client); | ||
2531 | GNUNET_free (zm); | ||
2532 | return; | ||
2533 | } | ||
2534 | zm->zone = zone; | ||
2535 | } | ||
2536 | zm->limit = 1; | ||
2537 | zm->filter = ntohs (zis_msg->filter); | ||
2538 | zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first)); | ||
2539 | GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm); | ||
2540 | GNUNET_SERVICE_client_mark_monitor (nc->client); | ||
2541 | GNUNET_SERVICE_client_continue (nc->client); | ||
2542 | GNUNET_notification_context_add (monitor_nc, nc->mq); | ||
2543 | if (zm->in_first_iteration) | ||
2544 | zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm); | ||
2545 | else | ||
2546 | monitor_sync (zm); | ||
2547 | } | ||
2548 | |||
2549 | |||
2550 | /** | ||
2551 | * Obtain the next datum during the zone monitor's zone initial iteration. | ||
2552 | * | ||
2553 | * @param cls zone monitor that does its initial iteration | ||
2554 | */ | ||
2555 | static void | ||
2556 | monitor_iteration_next (void *cls) | ||
2557 | { | ||
2558 | struct ZoneMonitor *zm = cls; | ||
2559 | struct NamestoreClient *nc = zm->nc; | ||
2560 | int ret; | ||
2561 | |||
2562 | zm->task = NULL; | ||
2563 | GNUNET_assert (0 == zm->iteration_cnt); | ||
2564 | if (zm->limit > 16) | ||
2565 | zm->iteration_cnt = zm->limit / 2; /* leave half for monitor events */ | ||
2566 | else | ||
2567 | zm->iteration_cnt = zm->limit; /* use it all */ | ||
2568 | zm->run_again = GNUNET_YES; | ||
2569 | while (GNUNET_YES == zm->run_again) | ||
2570 | { | ||
2571 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2572 | "Running iteration\n"); | ||
2573 | zm->run_again = GNUNET_NO; | ||
2574 | ret = nc->GSN_database->iterate_records (nc->GSN_database->cls, | ||
2575 | (GNUNET_YES == GNUNET_is_zero ( | ||
2576 | &zm->zone)) ? NULL : &zm->zone, | ||
2577 | zm->seq, | ||
2578 | zm->iteration_cnt, | ||
2579 | &monitor_iterate_cb, | ||
2580 | zm); | ||
2581 | } | ||
2582 | if (GNUNET_SYSERR == ret) | ||
2583 | { | ||
2584 | GNUNET_SERVICE_client_drop (zm->nc->client); | ||
2585 | return; | ||
2586 | } | ||
2587 | if (GNUNET_NO == ret) | ||
2588 | { | ||
2589 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2590 | "Zone empty... syncing\n"); | ||
2591 | /* empty zone */ | ||
2592 | monitor_sync (zm); | ||
2593 | return; | ||
2594 | } | ||
2595 | } | ||
2596 | |||
2597 | /** | ||
2598 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT message | ||
2599 | * | ||
2600 | * @param cls the client sending the message | ||
2601 | * @param nm message from the client | ||
2602 | */ | ||
2603 | static void | ||
2604 | handle_monitor_next (void *cls, const struct ZoneMonitorNextMessage *nm) | ||
2605 | { | ||
2606 | struct NamestoreClient *nc = cls; | ||
2607 | struct ZoneMonitor *zm; | ||
2608 | uint64_t inc; | ||
2609 | |||
2610 | inc = GNUNET_ntohll (nm->limit); | ||
2611 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2612 | "Received ZONE_MONITOR_NEXT message with limit %llu\n", | ||
2613 | (unsigned long long) inc); | ||
2614 | for (zm = monitor_head; NULL != zm; zm = zm->next) | ||
2615 | if (zm->nc == nc) | ||
2616 | break; | ||
2617 | if (NULL == zm) | ||
2618 | { | ||
2619 | GNUNET_break (0); | ||
2620 | GNUNET_SERVICE_client_drop (nc->client); | ||
2621 | return; | ||
2622 | } | ||
2623 | GNUNET_SERVICE_client_continue (nc->client); | ||
2624 | if (zm->limit + inc < zm->limit) | ||
2625 | { | ||
2626 | GNUNET_break (0); | ||
2627 | GNUNET_SERVICE_client_drop (nc->client); | ||
2628 | return; | ||
2629 | } | ||
2630 | zm->limit += inc; | ||
2631 | if ((zm->in_first_iteration) && (zm->limit == inc)) | ||
2632 | { | ||
2633 | /* We are still iterating, and the previous iteration must | ||
2634 | have stopped due to the client's limit, so continue it! */ | ||
2635 | GNUNET_assert (NULL == zm->task); | ||
2636 | zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm); | ||
2637 | } | ||
2638 | GNUNET_assert (zm->iteration_cnt <= zm->limit); | ||
2639 | if ((zm->limit > zm->iteration_cnt) && (zm->sa_waiting)) | ||
2640 | { | ||
2641 | monitor_unblock (zm); | ||
2642 | } | ||
2643 | else if (GNUNET_YES == zm->sa_waiting) | ||
2644 | { | ||
2645 | if (NULL != zm->sa_wait_warning) | ||
2646 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
2647 | zm->sa_waiting_start = GNUNET_TIME_absolute_get (); | ||
2648 | zm->sa_wait_warning = | ||
2649 | GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
2650 | &warn_monitor_slow, | ||
2651 | zm); | ||
2652 | } | ||
2653 | } | ||
2654 | |||
2655 | /** | ||
2656 | * Process namestore requests. | ||
2657 | * | ||
2658 | * @param cls closure | ||
2659 | * @param cfg configuration to use | ||
2660 | * @param service the initialized service | ||
2661 | */ | ||
2662 | static void | ||
2663 | run (void *cls, | ||
2664 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
2665 | struct GNUNET_SERVICE_Handle *service) | ||
2666 | { | ||
2667 | char *database; | ||
2668 | (void) cls; | ||
2669 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n"); | ||
2670 | return_orphaned = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
2671 | "namestore", | ||
2672 | "RETURN_ORPHANED"); | ||
2673 | GSN_cfg = cfg; | ||
2674 | monitor_nc = GNUNET_notification_context_create (1); | ||
2675 | statistics = GNUNET_STATISTICS_create ("namestore", cfg); | ||
2676 | /* Loading database plugin */ | ||
2677 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, | ||
2678 | "namestore", | ||
2679 | "database", | ||
2680 | &database)) | ||
2681 | { | ||
2682 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); | ||
2683 | GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); | ||
2684 | return; | ||
2685 | } | ||
2686 | GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database); | ||
2687 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading %s\n", db_lib_name); | ||
2688 | GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg); | ||
2689 | GNUNET_free (database); | ||
2690 | if (NULL == GSN_database) | ||
2691 | { | ||
2692 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2693 | "Could not load database backend `%s'\n", | ||
2694 | db_lib_name); | ||
2695 | GNUNET_free (db_lib_name); | ||
2696 | GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); | ||
2697 | return; | ||
2698 | } | ||
2699 | GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL); | ||
2700 | } | ||
2701 | |||
2702 | |||
2703 | /** | ||
2704 | * Define "main" method using service macro. | ||
2705 | */ | ||
2706 | GNUNET_SERVICE_MAIN ( | ||
2707 | "namestore", | ||
2708 | GNUNET_SERVICE_OPTION_NONE, | ||
2709 | &run, | ||
2710 | &client_connect_cb, | ||
2711 | &client_disconnect_cb, | ||
2712 | NULL, | ||
2713 | GNUNET_MQ_hd_fixed_size (tx_control, | ||
2714 | GNUNET_MESSAGE_TYPE_NAMESTORE_TX_CONTROL, | ||
2715 | struct TxControlMessage, | ||
2716 | NULL), | ||
2717 | GNUNET_MQ_hd_var_size (record_store, | ||
2718 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE, | ||
2719 | struct RecordStoreMessage, | ||
2720 | NULL), | ||
2721 | GNUNET_MQ_hd_var_size (record_lookup, | ||
2722 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP, | ||
2723 | struct LabelLookupMessage, | ||
2724 | NULL), | ||
2725 | GNUNET_MQ_hd_var_size (zone_to_name, | ||
2726 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, | ||
2727 | struct ZoneToNameMessage, | ||
2728 | NULL), | ||
2729 | GNUNET_MQ_hd_var_size (iteration_start, | ||
2730 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, | ||
2731 | struct ZoneIterationStartMessage, | ||
2732 | NULL), | ||
2733 | GNUNET_MQ_hd_fixed_size (iteration_next, | ||
2734 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, | ||
2735 | struct ZoneIterationNextMessage, | ||
2736 | NULL), | ||
2737 | GNUNET_MQ_hd_fixed_size (iteration_stop, | ||
2738 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, | ||
2739 | struct ZoneIterationStopMessage, | ||
2740 | NULL), | ||
2741 | GNUNET_MQ_hd_var_size (monitor_start, | ||
2742 | GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START, | ||
2743 | struct ZoneMonitorStartMessage, | ||
2744 | NULL), | ||
2745 | GNUNET_MQ_hd_fixed_size (monitor_next, | ||
2746 | GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT, | ||
2747 | struct ZoneMonitorNextMessage, | ||
2748 | NULL), | ||
2749 | GNUNET_MQ_handler_end ()); | ||
2750 | |||
2751 | |||
2752 | /* end of gnunet-service-namestore.c */ | ||