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