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