diff options
Diffstat (limited to 'src/namestore/gnunet-service-namestore.c')
-rw-r--r-- | src/namestore/gnunet-service-namestore.c | 2276 |
1 files changed, 0 insertions, 2276 deletions
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c deleted file mode 100644 index cd953492e..000000000 --- a/src/namestore/gnunet-service-namestore.c +++ /dev/null | |||
@@ -1,2276 +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 | /** | ||
126 | * A namestore client | ||
127 | */ | ||
128 | struct NamestoreClient | ||
129 | { | ||
130 | /** | ||
131 | * The client | ||
132 | */ | ||
133 | struct GNUNET_SERVICE_Client *client; | ||
134 | |||
135 | /** | ||
136 | * Message queue for transmission to @e client | ||
137 | */ | ||
138 | struct GNUNET_MQ_Handle *mq; | ||
139 | |||
140 | /** | ||
141 | * Head of the DLL of | ||
142 | * Zone iteration operations in progress initiated by this client | ||
143 | */ | ||
144 | struct ZoneIteration *op_head; | ||
145 | |||
146 | /** | ||
147 | * Tail of the DLL of | ||
148 | * Zone iteration operations in progress initiated by this client | ||
149 | */ | ||
150 | struct ZoneIteration *op_tail; | ||
151 | }; | ||
152 | |||
153 | |||
154 | /** | ||
155 | * A namestore monitor. | ||
156 | */ | ||
157 | struct ZoneMonitor | ||
158 | { | ||
159 | /** | ||
160 | * Next element in the DLL | ||
161 | */ | ||
162 | struct ZoneMonitor *next; | ||
163 | |||
164 | /** | ||
165 | * Previous element in the DLL | ||
166 | */ | ||
167 | struct ZoneMonitor *prev; | ||
168 | |||
169 | /** | ||
170 | * Namestore client which intiated this zone monitor | ||
171 | */ | ||
172 | struct NamestoreClient *nc; | ||
173 | |||
174 | /** | ||
175 | * Private key of the zone. | ||
176 | */ | ||
177 | struct GNUNET_IDENTITY_PrivateKey zone; | ||
178 | |||
179 | /** | ||
180 | * Task active during initial iteration. | ||
181 | */ | ||
182 | struct GNUNET_SCHEDULER_Task *task; | ||
183 | |||
184 | /** | ||
185 | * Task to warn about slow monitors. | ||
186 | */ | ||
187 | struct GNUNET_SCHEDULER_Task *sa_wait_warning; | ||
188 | |||
189 | /** | ||
190 | * Since when are we blocked on this monitor? | ||
191 | */ | ||
192 | struct GNUNET_TIME_Absolute sa_waiting_start; | ||
193 | |||
194 | /** | ||
195 | * Last sequence number in the zone iteration used to address next | ||
196 | * result of the zone iteration in the store | ||
197 | * | ||
198 | * Initially set to 0. | ||
199 | * Updated in #monitor_iterate_cb() | ||
200 | */ | ||
201 | uint64_t seq; | ||
202 | |||
203 | /** | ||
204 | * Current limit of how many more messages we are allowed | ||
205 | * to queue to this monitor. | ||
206 | */ | ||
207 | uint64_t limit; | ||
208 | |||
209 | /** | ||
210 | * How many more requests may we receive from the iterator | ||
211 | * before it is at the limit we gave it? Will be below or | ||
212 | * equal to @e limit. The effective limit for monitor | ||
213 | * events is thus @e iteration_cnt - @e limit! | ||
214 | */ | ||
215 | uint64_t iteration_cnt; | ||
216 | |||
217 | /** | ||
218 | * Are we (still) in the initial iteration pass? | ||
219 | */ | ||
220 | int in_first_iteration; | ||
221 | |||
222 | /** | ||
223 | * Is there a store activity waiting for this monitor? We only raise the | ||
224 | * flag when it happens and search the DLL for the store activity when we | ||
225 | * had a limit increase. If we cannot find any waiting store activity at | ||
226 | * that time, we clear the flag again. | ||
227 | */ | ||
228 | int sa_waiting; | ||
229 | }; | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Pending operation on the namecache. | ||
234 | */ | ||
235 | struct CacheOperation | ||
236 | { | ||
237 | /** | ||
238 | * Kept in a DLL. | ||
239 | */ | ||
240 | struct CacheOperation *prev; | ||
241 | |||
242 | /** | ||
243 | * Kept in a DLL. | ||
244 | */ | ||
245 | struct CacheOperation *next; | ||
246 | |||
247 | /** | ||
248 | * Handle to namecache queue. | ||
249 | */ | ||
250 | struct GNUNET_NAMECACHE_QueueEntry *qe; | ||
251 | |||
252 | /** | ||
253 | * Client to notify about the result, can be NULL. | ||
254 | */ | ||
255 | struct NamestoreClient *nc; | ||
256 | |||
257 | /** | ||
258 | * Zone iteration to call #zone_iteration_done_client_continue() | ||
259 | * for if applicable, can be NULL. | ||
260 | */ | ||
261 | struct ZoneIteration *zi; | ||
262 | |||
263 | /** | ||
264 | * Client's request ID. | ||
265 | */ | ||
266 | uint32_t rid; | ||
267 | }; | ||
268 | |||
269 | |||
270 | /** | ||
271 | * Information for an ongoing #handle_record_store() operation. | ||
272 | * Needed as we may wait for monitors to be ready for the notification. | ||
273 | */ | ||
274 | struct StoreActivity | ||
275 | { | ||
276 | /** | ||
277 | * Kept in a DLL. | ||
278 | */ | ||
279 | struct StoreActivity *next; | ||
280 | |||
281 | /** | ||
282 | * Kept in a DLL. | ||
283 | */ | ||
284 | struct StoreActivity *prev; | ||
285 | |||
286 | /** | ||
287 | * Which client triggered the store activity? | ||
288 | */ | ||
289 | struct NamestoreClient *nc; | ||
290 | |||
291 | /** | ||
292 | * Copy of the original store message (as data fields in @e rd will | ||
293 | * point into it!). | ||
294 | */ | ||
295 | const struct RecordStoreMessage *rsm; | ||
296 | |||
297 | /** | ||
298 | * Next zone monitor that still needs to be notified about this PUT. | ||
299 | */ | ||
300 | struct ZoneMonitor *zm_pos; | ||
301 | |||
302 | /** | ||
303 | * Label nicely canonicalized (lower case). | ||
304 | */ | ||
305 | char *conv_name; | ||
306 | }; | ||
307 | |||
308 | |||
309 | /** | ||
310 | * Entry in list of cached nick resolutions. | ||
311 | */ | ||
312 | struct NickCache | ||
313 | { | ||
314 | /** | ||
315 | * Zone the cache entry is for. | ||
316 | */ | ||
317 | struct GNUNET_IDENTITY_PrivateKey zone; | ||
318 | |||
319 | /** | ||
320 | * Cached record data. | ||
321 | */ | ||
322 | struct GNUNET_GNSRECORD_Data *rd; | ||
323 | |||
324 | /** | ||
325 | * Timestamp when this cache entry was used last. | ||
326 | */ | ||
327 | struct GNUNET_TIME_Absolute last_used; | ||
328 | }; | ||
329 | |||
330 | |||
331 | /** | ||
332 | * We cache nick records to reduce DB load. | ||
333 | */ | ||
334 | static struct NickCache nick_cache[NC_SIZE]; | ||
335 | |||
336 | /** | ||
337 | * Public key of all zeros. | ||
338 | */ | ||
339 | static const struct GNUNET_IDENTITY_PrivateKey zero; | ||
340 | |||
341 | /** | ||
342 | * Configuration handle. | ||
343 | */ | ||
344 | static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg; | ||
345 | |||
346 | /** | ||
347 | * Handle to the statistics service | ||
348 | */ | ||
349 | static struct GNUNET_STATISTICS_Handle *statistics; | ||
350 | |||
351 | /** | ||
352 | * Namecache handle. | ||
353 | */ | ||
354 | static struct GNUNET_NAMECACHE_Handle *namecache; | ||
355 | |||
356 | /** | ||
357 | * Database handle | ||
358 | */ | ||
359 | static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; | ||
360 | |||
361 | /** | ||
362 | * Name of the database plugin | ||
363 | */ | ||
364 | static char *db_lib_name; | ||
365 | |||
366 | /** | ||
367 | * Head of cop DLL. | ||
368 | */ | ||
369 | static struct CacheOperation *cop_head; | ||
370 | |||
371 | /** | ||
372 | * Tail of cop DLL. | ||
373 | */ | ||
374 | static struct CacheOperation *cop_tail; | ||
375 | |||
376 | /** | ||
377 | * First active zone monitor. | ||
378 | */ | ||
379 | static struct ZoneMonitor *monitor_head; | ||
380 | |||
381 | /** | ||
382 | * Last active zone monitor. | ||
383 | */ | ||
384 | static struct ZoneMonitor *monitor_tail; | ||
385 | |||
386 | /** | ||
387 | * Head of DLL of monitor-blocked store activities. | ||
388 | */ | ||
389 | static struct StoreActivity *sa_head; | ||
390 | |||
391 | /** | ||
392 | * Tail of DLL of monitor-blocked store activities. | ||
393 | */ | ||
394 | static struct StoreActivity *sa_tail; | ||
395 | |||
396 | /** | ||
397 | * Notification context shared by all monitors. | ||
398 | */ | ||
399 | static struct GNUNET_NotificationContext *monitor_nc; | ||
400 | |||
401 | /** | ||
402 | * Optimize block insertion by caching map of private keys to | ||
403 | * public keys in memory? | ||
404 | */ | ||
405 | static int cache_keys; | ||
406 | |||
407 | /** | ||
408 | * Use the namecache? Doing so creates additional cryptographic | ||
409 | * operations whenever we touch a record. | ||
410 | */ | ||
411 | static int disable_namecache; | ||
412 | |||
413 | |||
414 | /** | ||
415 | * Task run during shutdown. | ||
416 | * | ||
417 | * @param cls unused | ||
418 | */ | ||
419 | static void | ||
420 | cleanup_task (void *cls) | ||
421 | { | ||
422 | struct CacheOperation *cop; | ||
423 | |||
424 | (void) cls; | ||
425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n"); | ||
426 | while (NULL != (cop = cop_head)) | ||
427 | { | ||
428 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
429 | "Aborting incomplete namecache operation\n"); | ||
430 | GNUNET_NAMECACHE_cancel (cop->qe); | ||
431 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); | ||
432 | GNUNET_free (cop); | ||
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, uint32_t rid) | ||
812 | { | ||
813 | struct GNUNET_MQ_Envelope *env; | ||
814 | struct RecordStoreResponseMessage *rcr_msg; | ||
815 | |||
816 | GNUNET_assert (NULL != nc); | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
818 | "Sending RECORD_STORE_RESPONSE message\n"); | ||
819 | GNUNET_STATISTICS_update (statistics, | ||
820 | "Store requests completed", | ||
821 | 1, | ||
822 | GNUNET_NO); | ||
823 | env = GNUNET_MQ_msg (rcr_msg, | ||
824 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE); | ||
825 | rcr_msg->gns_header.r_id = htonl (rid); | ||
826 | rcr_msg->op_result = htonl (res); | ||
827 | GNUNET_MQ_send (nc->mq, env); | ||
828 | } | ||
829 | |||
830 | |||
831 | /** | ||
832 | * Function called once we are done with the zone iteration and | ||
833 | * allow the zone iteration client to send us more messages. | ||
834 | * | ||
835 | * @param zi zone iteration we are processing | ||
836 | */ | ||
837 | static void | ||
838 | zone_iteration_done_client_continue (struct ZoneIteration *zi) | ||
839 | { | ||
840 | struct GNUNET_MQ_Envelope *env; | ||
841 | struct GNUNET_NAMESTORE_Header *em; | ||
842 | |||
843 | GNUNET_SERVICE_client_continue (zi->nc->client); | ||
844 | if (! zi->send_end) | ||
845 | return; | ||
846 | /* send empty response to indicate end of list */ | ||
847 | env = GNUNET_MQ_msg (em, GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END); | ||
848 | em->r_id = htonl (zi->request_id); | ||
849 | GNUNET_MQ_send (zi->nc->mq, env); | ||
850 | |||
851 | GNUNET_CONTAINER_DLL_remove (zi->nc->op_head, zi->nc->op_tail, zi); | ||
852 | GNUNET_free (zi); | ||
853 | } | ||
854 | |||
855 | |||
856 | /** | ||
857 | * Cache operation complete, clean up. | ||
858 | * | ||
859 | * @param cls the `struct CacheOperation` | ||
860 | * @param success success | ||
861 | * @param emsg error messages | ||
862 | */ | ||
863 | static void | ||
864 | finish_cache_operation (void *cls, int32_t success, const char *emsg) | ||
865 | { | ||
866 | struct CacheOperation *cop = cls; | ||
867 | struct ZoneIteration *zi; | ||
868 | |||
869 | if (NULL != emsg) | ||
870 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
871 | _ ("Failed to replicate block in namecache: %s\n"), | ||
872 | emsg); | ||
873 | else | ||
874 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CACHE operation completed\n"); | ||
875 | GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop); | ||
876 | if (NULL != cop->nc) | ||
877 | send_store_response (cop->nc, success, cop->rid); | ||
878 | if (NULL != (zi = cop->zi)) | ||
879 | { | ||
880 | zi->cache_ops--; | ||
881 | if (0 == zi->cache_ops) | ||
882 | { | ||
883 | /* unchoke zone iteration, cache has caught up */ | ||
884 | zone_iteration_done_client_continue (zi); | ||
885 | } | ||
886 | } | ||
887 | GNUNET_free (cop); | ||
888 | } | ||
889 | |||
890 | |||
891 | /** | ||
892 | * We just touched the plaintext information about a name in our zone; | ||
893 | * refresh the corresponding (encrypted) block in the namecache. | ||
894 | * | ||
895 | * @param nc client responsible for the request, can be NULL | ||
896 | * @param zi zone iteration response for the request, can be NULL | ||
897 | * @param rid request ID of the client | ||
898 | * @param zone_key private key of the zone | ||
899 | * @param name label for the records | ||
900 | * @param rd_count number of records | ||
901 | * @param rd records stored under the given @a name | ||
902 | */ | ||
903 | static void | ||
904 | refresh_block (struct NamestoreClient *nc, | ||
905 | struct ZoneIteration *zi, | ||
906 | uint32_t rid, | ||
907 | const struct GNUNET_IDENTITY_PrivateKey *zone_key, | ||
908 | const char *name, | ||
909 | unsigned int rd_count, | ||
910 | const struct GNUNET_GNSRECORD_Data *rd) | ||
911 | { | ||
912 | struct GNUNET_GNSRECORD_Block *block; | ||
913 | struct CacheOperation *cop; | ||
914 | struct GNUNET_IDENTITY_PublicKey pkey; | ||
915 | struct GNUNET_GNSRECORD_Data *nick; | ||
916 | struct GNUNET_GNSRECORD_Data *res; | ||
917 | unsigned int res_count; | ||
918 | struct GNUNET_TIME_Absolute exp_time; | ||
919 | |||
920 | nick = get_nick_record (zone_key); | ||
921 | res_count = rd_count; | ||
922 | res = (struct GNUNET_GNSRECORD_Data *) rd; /* fixme: a bit unclean... */ | ||
923 | if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) | ||
924 | { | ||
925 | nick->flags = | ||
926 | (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE; | ||
927 | merge_with_nick_records (nick, rd_count, rd, &res_count, &res); | ||
928 | } | ||
929 | if (NULL != nick) | ||
930 | GNUNET_free (nick); | ||
931 | if (0 == res_count) | ||
932 | { | ||
933 | if (NULL != nc) | ||
934 | send_store_response (nc, GNUNET_OK, rid); | ||
935 | if (rd != res) | ||
936 | GNUNET_free (res); | ||
937 | return; /* no data, no need to update cache */ | ||
938 | } | ||
939 | if (GNUNET_YES == disable_namecache) | ||
940 | { | ||
941 | GNUNET_STATISTICS_update (statistics, | ||
942 | "Namecache updates skipped (NC disabled)", | ||
943 | 1, | ||
944 | GNUNET_NO); | ||
945 | if (NULL != nc) | ||
946 | send_store_response (nc, GNUNET_OK, rid); | ||
947 | if (rd != res) | ||
948 | GNUNET_free (res); | ||
949 | return; | ||
950 | } | ||
951 | exp_time = GNUNET_GNSRECORD_record_get_expiration_time (res_count, res); | ||
952 | if (cache_keys) | ||
953 | block = | ||
954 | GNUNET_GNSRECORD_block_create2 (zone_key, exp_time, name, res, res_count); | ||
955 | else | ||
956 | block = | ||
957 | GNUNET_GNSRECORD_block_create (zone_key, exp_time, name, res, res_count); | ||
958 | GNUNET_assert (NULL != block); | ||
959 | GNUNET_IDENTITY_key_get_public (zone_key, &pkey); | ||
960 | GNUNET_log ( | ||
961 | GNUNET_ERROR_TYPE_DEBUG, | ||
962 | "Caching block for label `%s' with %u records and expiration %s in zone `%s' in namecache\n", | ||
963 | name, | ||
964 | res_count, | ||
965 | GNUNET_STRINGS_absolute_time_to_string (exp_time), | ||
966 | GNUNET_GNSRECORD_z2s (&pkey)); | ||
967 | GNUNET_STATISTICS_update (statistics, | ||
968 | "Namecache updates pushed", | ||
969 | 1, | ||
970 | GNUNET_NO); | ||
971 | cop = GNUNET_new (struct CacheOperation); | ||
972 | cop->nc = nc; | ||
973 | cop->zi = zi; | ||
974 | if (NULL != zi) | ||
975 | zi->cache_ops++; | ||
976 | cop->rid = rid; | ||
977 | GNUNET_CONTAINER_DLL_insert (cop_head, cop_tail, cop); | ||
978 | cop->qe = GNUNET_NAMECACHE_block_cache (namecache, | ||
979 | block, | ||
980 | &finish_cache_operation, | ||
981 | cop); | ||
982 | GNUNET_free (block); | ||
983 | if (rd != res) | ||
984 | GNUNET_free (res); | ||
985 | } | ||
986 | |||
987 | |||
988 | /** | ||
989 | * Print a warning that one of our monitors is no longer reacting. | ||
990 | * | ||
991 | * @param cls a `struct ZoneMonitor` to warn about | ||
992 | */ | ||
993 | static void | ||
994 | warn_monitor_slow (void *cls) | ||
995 | { | ||
996 | struct ZoneMonitor *zm = cls; | ||
997 | |||
998 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
999 | "No response from monitor since %s\n", | ||
1000 | GNUNET_STRINGS_absolute_time_to_string (zm->sa_waiting_start)); | ||
1001 | zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
1002 | &warn_monitor_slow, | ||
1003 | zm); | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | /** | ||
1008 | * Continue processing the @a sa. | ||
1009 | * | ||
1010 | * @param sa store activity to process | ||
1011 | */ | ||
1012 | static void | ||
1013 | continue_store_activity (struct StoreActivity *sa) | ||
1014 | { | ||
1015 | const struct RecordStoreMessage *rp_msg = sa->rsm; | ||
1016 | unsigned int rd_count; | ||
1017 | size_t name_len; | ||
1018 | size_t rd_ser_len; | ||
1019 | uint32_t rid; | ||
1020 | const char *name_tmp; | ||
1021 | const char *rd_ser; | ||
1022 | |||
1023 | rid = ntohl (rp_msg->gns_header.r_id); | ||
1024 | name_len = ntohs (rp_msg->name_len); | ||
1025 | rd_count = ntohs (rp_msg->rd_count); | ||
1026 | rd_ser_len = ntohs (rp_msg->rd_len); | ||
1027 | name_tmp = (const char *) &rp_msg[1]; | ||
1028 | rd_ser = &name_tmp[name_len]; | ||
1029 | { | ||
1030 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; | ||
1031 | |||
1032 | /* We did this before, must succeed again */ | ||
1033 | GNUNET_assert ( | ||
1034 | GNUNET_OK == | ||
1035 | GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, rd)); | ||
1036 | |||
1037 | for (struct ZoneMonitor *zm = sa->zm_pos; NULL != zm; zm = sa->zm_pos) | ||
1038 | { | ||
1039 | if ((0 != GNUNET_memcmp (&rp_msg->private_key, &zm->zone)) && | ||
1040 | (0 != GNUNET_memcmp (&zm->zone, &zero))) | ||
1041 | { | ||
1042 | sa->zm_pos = zm->next; /* not interesting to this monitor */ | ||
1043 | continue; | ||
1044 | } | ||
1045 | if (zm->limit == zm->iteration_cnt) | ||
1046 | { | ||
1047 | zm->sa_waiting = GNUNET_YES; | ||
1048 | zm->sa_waiting_start = GNUNET_TIME_absolute_get (); | ||
1049 | if (NULL != zm->sa_wait_warning) | ||
1050 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
1051 | zm->sa_wait_warning = | ||
1052 | GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
1053 | &warn_monitor_slow, | ||
1054 | zm); | ||
1055 | return; /* blocked on zone monitor */ | ||
1056 | } | ||
1057 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1058 | "Notifying monitor about changes under label `%s'\n", | ||
1059 | sa->conv_name); | ||
1060 | zm->limit--; | ||
1061 | send_lookup_response (zm->nc, | ||
1062 | 0, | ||
1063 | &rp_msg->private_key, | ||
1064 | sa->conv_name, | ||
1065 | rd_count, | ||
1066 | rd); | ||
1067 | sa->zm_pos = zm->next; | ||
1068 | } | ||
1069 | /* great, done with the monitors, unpack (again) for refresh_block operation */ | ||
1070 | refresh_block (sa->nc, | ||
1071 | NULL, | ||
1072 | rid, | ||
1073 | &rp_msg->private_key, | ||
1074 | sa->conv_name, | ||
1075 | rd_count, | ||
1076 | rd); | ||
1077 | } | ||
1078 | GNUNET_SERVICE_client_continue (sa->nc->client); | ||
1079 | free_store_activity (sa); | ||
1080 | } | ||
1081 | |||
1082 | |||
1083 | /** | ||
1084 | * Called whenever a client is disconnected. | ||
1085 | * Frees our resources associated with that client. | ||
1086 | * | ||
1087 | * @param cls closure | ||
1088 | * @param client identification of the client | ||
1089 | * @param app_ctx the `struct NamestoreClient` of @a client | ||
1090 | */ | ||
1091 | static void | ||
1092 | client_disconnect_cb (void *cls, | ||
1093 | struct GNUNET_SERVICE_Client *client, | ||
1094 | void *app_ctx) | ||
1095 | { | ||
1096 | struct NamestoreClient *nc = app_ctx; | ||
1097 | struct ZoneIteration *no; | ||
1098 | struct CacheOperation *cop; | ||
1099 | |||
1100 | (void) cls; | ||
1101 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client); | ||
1102 | for (struct ZoneMonitor *zm = monitor_head; NULL != zm; zm = zm->next) | ||
1103 | { | ||
1104 | struct StoreActivity *san; | ||
1105 | |||
1106 | if (nc != zm->nc) | ||
1107 | continue; | ||
1108 | GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, zm); | ||
1109 | if (NULL != zm->task) | ||
1110 | { | ||
1111 | GNUNET_SCHEDULER_cancel (zm->task); | ||
1112 | zm->task = NULL; | ||
1113 | } | ||
1114 | if (NULL != zm->sa_wait_warning) | ||
1115 | { | ||
1116 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
1117 | zm->sa_wait_warning = NULL; | ||
1118 | } | ||
1119 | for (struct StoreActivity *sa = sa_head; NULL != sa; sa = san) | ||
1120 | { | ||
1121 | san = sa->next; | ||
1122 | if (zm == sa->zm_pos) | ||
1123 | { | ||
1124 | sa->zm_pos = zm->next; | ||
1125 | /* this may free sa */ | ||
1126 | continue_store_activity (sa); | ||
1127 | } | ||
1128 | } | ||
1129 | GNUNET_free (zm); | ||
1130 | break; | ||
1131 | } | ||
1132 | for (struct StoreActivity *sa = sa_head; NULL != sa; sa = sa->next) | ||
1133 | { | ||
1134 | if (sa->nc == nc) | ||
1135 | { | ||
1136 | /* this may free sa */ | ||
1137 | free_store_activity (sa); | ||
1138 | break; /* there can only be one per nc */ | ||
1139 | } | ||
1140 | } | ||
1141 | while (NULL != (no = nc->op_head)) | ||
1142 | { | ||
1143 | GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no); | ||
1144 | GNUNET_free (no); | ||
1145 | } | ||
1146 | for (cop = cop_head; NULL != cop; cop = cop->next) | ||
1147 | if (nc == cop->nc) | ||
1148 | cop->nc = NULL; | ||
1149 | GNUNET_free (nc); | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | /** | ||
1154 | * Add a client to our list of active clients. | ||
1155 | * | ||
1156 | * @param cls NULL | ||
1157 | * @param client client to add | ||
1158 | * @param mq message queue for @a client | ||
1159 | * @return internal namestore client structure for this client | ||
1160 | */ | ||
1161 | static void * | ||
1162 | client_connect_cb (void *cls, | ||
1163 | struct GNUNET_SERVICE_Client *client, | ||
1164 | struct GNUNET_MQ_Handle *mq) | ||
1165 | { | ||
1166 | struct NamestoreClient *nc; | ||
1167 | |||
1168 | (void) cls; | ||
1169 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); | ||
1170 | nc = GNUNET_new (struct NamestoreClient); | ||
1171 | nc->client = client; | ||
1172 | nc->mq = mq; | ||
1173 | return nc; | ||
1174 | } | ||
1175 | |||
1176 | |||
1177 | /** | ||
1178 | * Closure for #lookup_it(). | ||
1179 | */ | ||
1180 | struct RecordLookupContext | ||
1181 | { | ||
1182 | /** | ||
1183 | * FIXME. | ||
1184 | */ | ||
1185 | const char *label; | ||
1186 | |||
1187 | /** | ||
1188 | * FIXME. | ||
1189 | */ | ||
1190 | char *res_rd; | ||
1191 | |||
1192 | /** | ||
1193 | * FIXME. | ||
1194 | */ | ||
1195 | struct GNUNET_GNSRECORD_Data *nick; | ||
1196 | |||
1197 | /** | ||
1198 | * FIXME. | ||
1199 | */ | ||
1200 | int found; | ||
1201 | |||
1202 | /** | ||
1203 | * FIXME. | ||
1204 | */ | ||
1205 | unsigned int res_rd_count; | ||
1206 | |||
1207 | /** | ||
1208 | * FIXME. | ||
1209 | */ | ||
1210 | ssize_t rd_ser_len; | ||
1211 | }; | ||
1212 | |||
1213 | |||
1214 | /** | ||
1215 | * Function called by the namestore plugin when we are trying to lookup | ||
1216 | * a record as part of #handle_record_lookup(). Merges all results into | ||
1217 | * the context. | ||
1218 | * | ||
1219 | * @param cls closure with a `struct RecordLookupContext` | ||
1220 | * @param seq unique serial number of the record, MUST NOT BE ZERO | ||
1221 | * @param zone_key private key of the zone | ||
1222 | * @param label name that is being mapped (at most 255 characters long) | ||
1223 | * @param rd_count number of entries in @a rd array | ||
1224 | * @param rd array of records with data to store | ||
1225 | */ | ||
1226 | static void | ||
1227 | lookup_it (void *cls, | ||
1228 | uint64_t seq, | ||
1229 | const struct GNUNET_IDENTITY_PrivateKey *private_key, | ||
1230 | const char *label, | ||
1231 | unsigned int rd_count, | ||
1232 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1233 | { | ||
1234 | struct RecordLookupContext *rlc = cls; | ||
1235 | |||
1236 | (void) private_key; | ||
1237 | GNUNET_assert (0 != seq); | ||
1238 | if (0 != strcmp (label, rlc->label)) | ||
1239 | return; | ||
1240 | rlc->found = GNUNET_YES; | ||
1241 | if (0 == rd_count) | ||
1242 | { | ||
1243 | rlc->rd_ser_len = 0; | ||
1244 | rlc->res_rd_count = 0; | ||
1245 | rlc->res_rd = NULL; | ||
1246 | return; | ||
1247 | } | ||
1248 | if ((NULL != rlc->nick) && (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))) | ||
1249 | { | ||
1250 | /* Merge */ | ||
1251 | struct GNUNET_GNSRECORD_Data *rd_res; | ||
1252 | unsigned int rdc_res; | ||
1253 | |||
1254 | rd_res = NULL; | ||
1255 | rdc_res = 0; | ||
1256 | rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) | ||
1257 | ^ GNUNET_GNSRECORD_RF_PRIVATE; | ||
1258 | merge_with_nick_records (rlc->nick, rd_count, rd, &rdc_res, &rd_res); | ||
1259 | rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res, rd_res); | ||
1260 | if (rlc->rd_ser_len < 0) | ||
1261 | { | ||
1262 | GNUNET_break (0); | ||
1263 | GNUNET_free (rd_res); | ||
1264 | rlc->found = GNUNET_NO; | ||
1265 | rlc->rd_ser_len = 0; | ||
1266 | return; | ||
1267 | } | ||
1268 | rlc->res_rd_count = rdc_res; | ||
1269 | rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len); | ||
1270 | if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rdc_res, | ||
1271 | rd_res, | ||
1272 | rlc->rd_ser_len, | ||
1273 | rlc->res_rd)) | ||
1274 | { | ||
1275 | GNUNET_break (0); | ||
1276 | GNUNET_free (rlc->res_rd); | ||
1277 | rlc->res_rd = NULL; | ||
1278 | rlc->res_rd_count = 0; | ||
1279 | rlc->rd_ser_len = 0; | ||
1280 | GNUNET_free (rd_res); | ||
1281 | rlc->found = GNUNET_NO; | ||
1282 | return; | ||
1283 | } | ||
1284 | GNUNET_free (rd_res); | ||
1285 | GNUNET_free (rlc->nick); | ||
1286 | rlc->nick = NULL; | ||
1287 | } | ||
1288 | else | ||
1289 | { | ||
1290 | rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | ||
1291 | if (rlc->rd_ser_len < 0) | ||
1292 | { | ||
1293 | GNUNET_break (0); | ||
1294 | rlc->found = GNUNET_NO; | ||
1295 | rlc->rd_ser_len = 0; | ||
1296 | return; | ||
1297 | } | ||
1298 | rlc->res_rd_count = rd_count; | ||
1299 | rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len); | ||
1300 | if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rd_count, | ||
1301 | rd, | ||
1302 | rlc->rd_ser_len, | ||
1303 | rlc->res_rd)) | ||
1304 | { | ||
1305 | GNUNET_break (0); | ||
1306 | GNUNET_free (rlc->res_rd); | ||
1307 | rlc->res_rd = NULL; | ||
1308 | rlc->res_rd_count = 0; | ||
1309 | rlc->rd_ser_len = 0; | ||
1310 | rlc->found = GNUNET_NO; | ||
1311 | return; | ||
1312 | } | ||
1313 | } | ||
1314 | } | ||
1315 | |||
1316 | |||
1317 | /** | ||
1318 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message | ||
1319 | * | ||
1320 | * @param cls client sending the message | ||
1321 | * @param ll_msg message of type `struct LabelLookupMessage` | ||
1322 | * @return #GNUNET_OK if @a ll_msg is well-formed | ||
1323 | */ | ||
1324 | static int | ||
1325 | check_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | ||
1326 | { | ||
1327 | uint32_t name_len; | ||
1328 | size_t src_size; | ||
1329 | |||
1330 | (void) cls; | ||
1331 | name_len = ntohl (ll_msg->label_len); | ||
1332 | src_size = ntohs (ll_msg->gns_header.header.size); | ||
1333 | if (name_len != src_size - sizeof(struct LabelLookupMessage)) | ||
1334 | { | ||
1335 | GNUNET_break (0); | ||
1336 | return GNUNET_SYSERR; | ||
1337 | } | ||
1338 | GNUNET_MQ_check_zero_termination (ll_msg); | ||
1339 | return GNUNET_OK; | ||
1340 | } | ||
1341 | |||
1342 | |||
1343 | /** | ||
1344 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message | ||
1345 | * | ||
1346 | * @param cls client sending the message | ||
1347 | * @param ll_msg message of type `struct LabelLookupMessage` | ||
1348 | */ | ||
1349 | static void | ||
1350 | handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | ||
1351 | { | ||
1352 | struct NamestoreClient *nc = cls; | ||
1353 | struct GNUNET_MQ_Envelope *env; | ||
1354 | struct LabelLookupResponseMessage *llr_msg; | ||
1355 | struct RecordLookupContext rlc; | ||
1356 | const char *name_tmp; | ||
1357 | char *res_name; | ||
1358 | char *conv_name; | ||
1359 | uint32_t name_len; | ||
1360 | int res; | ||
1361 | |||
1362 | name_len = ntohl (ll_msg->label_len); | ||
1363 | name_tmp = (const char *) &ll_msg[1]; | ||
1364 | GNUNET_SERVICE_client_continue (nc->client); | ||
1365 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1366 | "Received NAMESTORE_RECORD_LOOKUP message for name `%s'\n", | ||
1367 | name_tmp); | ||
1368 | |||
1369 | conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp); | ||
1370 | if (NULL == conv_name) | ||
1371 | { | ||
1372 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1373 | "Error converting name `%s'\n", | ||
1374 | name_tmp); | ||
1375 | GNUNET_SERVICE_client_drop (nc->client); | ||
1376 | return; | ||
1377 | } | ||
1378 | rlc.label = conv_name; | ||
1379 | rlc.found = GNUNET_NO; | ||
1380 | rlc.res_rd_count = 0; | ||
1381 | rlc.res_rd = NULL; | ||
1382 | rlc.rd_ser_len = 0; | ||
1383 | rlc.nick = get_nick_record (&ll_msg->zone); | ||
1384 | res = GSN_database->lookup_records (GSN_database->cls, | ||
1385 | &ll_msg->zone, | ||
1386 | conv_name, | ||
1387 | &lookup_it, | ||
1388 | &rlc); | ||
1389 | GNUNET_free (conv_name); | ||
1390 | env = | ||
1391 | GNUNET_MQ_msg_extra (llr_msg, | ||
1392 | name_len + rlc.rd_ser_len, | ||
1393 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE); | ||
1394 | llr_msg->gns_header.r_id = ll_msg->gns_header.r_id; | ||
1395 | llr_msg->private_key = ll_msg->zone; | ||
1396 | llr_msg->name_len = htons (name_len); | ||
1397 | llr_msg->rd_count = htons (rlc.res_rd_count); | ||
1398 | llr_msg->rd_len = htons (rlc.rd_ser_len); | ||
1399 | res_name = (char *) &llr_msg[1]; | ||
1400 | if ((GNUNET_YES == rlc.found) && (GNUNET_OK == res)) | ||
1401 | llr_msg->found = ntohs (GNUNET_YES); | ||
1402 | else | ||
1403 | llr_msg->found = ntohs (GNUNET_NO); | ||
1404 | GNUNET_memcpy (&llr_msg[1], name_tmp, name_len); | ||
1405 | GNUNET_memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len); | ||
1406 | GNUNET_MQ_send (nc->mq, env); | ||
1407 | GNUNET_free (rlc.res_rd); | ||
1408 | } | ||
1409 | |||
1410 | |||
1411 | /** | ||
1412 | * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message | ||
1413 | * | ||
1414 | * @param cls client sending the message | ||
1415 | * @param rp_msg message of type `struct RecordStoreMessage` | ||
1416 | * @return #GNUNET_OK if @a rp_msg is well-formed | ||
1417 | */ | ||
1418 | static int | ||
1419 | check_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | ||
1420 | { | ||
1421 | size_t name_len; | ||
1422 | size_t msg_size; | ||
1423 | size_t msg_size_exp; | ||
1424 | size_t rd_ser_len; | ||
1425 | const char *name_tmp; | ||
1426 | |||
1427 | (void) cls; | ||
1428 | name_len = ntohs (rp_msg->name_len); | ||
1429 | msg_size = ntohs (rp_msg->gns_header.header.size); | ||
1430 | rd_ser_len = ntohs (rp_msg->rd_len); | ||
1431 | msg_size_exp = sizeof(struct RecordStoreMessage) + name_len + rd_ser_len; | ||
1432 | if (msg_size != msg_size_exp) | ||
1433 | { | ||
1434 | GNUNET_break (0); | ||
1435 | return GNUNET_SYSERR; | ||
1436 | } | ||
1437 | if ((0 == name_len) || (name_len > MAX_NAME_LEN)) | ||
1438 | { | ||
1439 | GNUNET_break (0); | ||
1440 | return GNUNET_SYSERR; | ||
1441 | } | ||
1442 | name_tmp = (const char *) &rp_msg[1]; | ||
1443 | if ('\0' != name_tmp[name_len - 1]) | ||
1444 | { | ||
1445 | GNUNET_break (0); | ||
1446 | return GNUNET_SYSERR; | ||
1447 | } | ||
1448 | return GNUNET_OK; | ||
1449 | } | ||
1450 | |||
1451 | |||
1452 | /** | ||
1453 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message | ||
1454 | * | ||
1455 | * @param cls client sending the message | ||
1456 | * @param rp_msg message of type `struct RecordStoreMessage` | ||
1457 | */ | ||
1458 | static void | ||
1459 | handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) | ||
1460 | { | ||
1461 | struct NamestoreClient *nc = cls; | ||
1462 | size_t name_len; | ||
1463 | size_t rd_ser_len; | ||
1464 | uint32_t rid; | ||
1465 | const char *name_tmp; | ||
1466 | char *conv_name; | ||
1467 | const char *rd_ser; | ||
1468 | unsigned int rd_count; | ||
1469 | int res; | ||
1470 | struct StoreActivity *sa; | ||
1471 | |||
1472 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1473 | "Received NAMESTORE_RECORD_STORE message\n"); | ||
1474 | rid = ntohl (rp_msg->gns_header.r_id); | ||
1475 | name_len = ntohs (rp_msg->name_len); | ||
1476 | rd_count = ntohs (rp_msg->rd_count); | ||
1477 | rd_ser_len = ntohs (rp_msg->rd_len); | ||
1478 | GNUNET_break (0 == ntohs (rp_msg->reserved)); | ||
1479 | name_tmp = (const char *) &rp_msg[1]; | ||
1480 | rd_ser = &name_tmp[name_len]; | ||
1481 | { | ||
1482 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; | ||
1483 | |||
1484 | if (GNUNET_OK != | ||
1485 | GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, rd)) | ||
1486 | { | ||
1487 | GNUNET_break (0); | ||
1488 | GNUNET_SERVICE_client_drop (nc->client); | ||
1489 | return; | ||
1490 | } | ||
1491 | |||
1492 | /* Extracting and converting private key */ | ||
1493 | conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp); | ||
1494 | if (NULL == conv_name) | ||
1495 | { | ||
1496 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1497 | "Error converting name `%s'\n", | ||
1498 | name_tmp); | ||
1499 | GNUNET_SERVICE_client_drop (nc->client); | ||
1500 | return; | ||
1501 | } | ||
1502 | GNUNET_STATISTICS_update (statistics, | ||
1503 | "Well-formed store requests received", | ||
1504 | 1, | ||
1505 | GNUNET_NO); | ||
1506 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1507 | "Creating %u records for name `%s'\n", | ||
1508 | (unsigned int) rd_count, | ||
1509 | conv_name); | ||
1510 | if ((0 == rd_count) && | ||
1511 | (GNUNET_NO == GSN_database->lookup_records (GSN_database->cls, | ||
1512 | &rp_msg->private_key, | ||
1513 | conv_name, | ||
1514 | NULL, | ||
1515 | 0))) | ||
1516 | { | ||
1517 | /* This name does not exist, so cannot be removed */ | ||
1518 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1519 | "Name `%s' does not exist, no deletion required\n", | ||
1520 | conv_name); | ||
1521 | res = GNUNET_NO; | ||
1522 | } | ||
1523 | else | ||
1524 | { | ||
1525 | /* remove "NICK" records, unless this is for the | ||
1526 | #GNUNET_GNS_EMPTY_LABEL_AT label */ | ||
1527 | struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count)]; | ||
1528 | unsigned int rd_clean_off; | ||
1529 | int have_nick; | ||
1530 | |||
1531 | rd_clean_off = 0; | ||
1532 | have_nick = GNUNET_NO; | ||
1533 | for (unsigned int i = 0; i < rd_count; i++) | ||
1534 | { | ||
1535 | rd_clean[rd_clean_off] = rd[i]; | ||
1536 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) || | ||
1537 | (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type)) | ||
1538 | rd_clean_off++; | ||
1539 | |||
1540 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && | ||
1541 | (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type)) | ||
1542 | { | ||
1543 | cache_nick (&rp_msg->private_key, &rd[i]); | ||
1544 | have_nick = GNUNET_YES; | ||
1545 | } | ||
1546 | } | ||
1547 | if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) && | ||
1548 | (GNUNET_NO == have_nick)) | ||
1549 | { | ||
1550 | /* remove nick record from cache, in case we have one there */ | ||
1551 | cache_nick (&rp_msg->private_key, NULL); | ||
1552 | } | ||
1553 | res = GSN_database->store_records (GSN_database->cls, | ||
1554 | &rp_msg->private_key, | ||
1555 | conv_name, | ||
1556 | rd_clean_off, | ||
1557 | rd_clean); | ||
1558 | } | ||
1559 | |||
1560 | if (GNUNET_OK != res) | ||
1561 | { | ||
1562 | /* store not successful, not need to tell monitors */ | ||
1563 | send_store_response (nc, res, rid); | ||
1564 | GNUNET_SERVICE_client_continue (nc->client); | ||
1565 | GNUNET_free (conv_name); | ||
1566 | return; | ||
1567 | } | ||
1568 | |||
1569 | sa = GNUNET_malloc (sizeof(struct StoreActivity) | ||
1570 | + ntohs (rp_msg->gns_header.header.size)); | ||
1571 | GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa); | ||
1572 | sa->nc = nc; | ||
1573 | sa->rsm = (const struct RecordStoreMessage *) &sa[1]; | ||
1574 | GNUNET_memcpy (&sa[1], rp_msg, ntohs (rp_msg->gns_header.header.size)); | ||
1575 | sa->zm_pos = monitor_head; | ||
1576 | sa->conv_name = conv_name; | ||
1577 | continue_store_activity (sa); | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1581 | |||
1582 | /** | ||
1583 | * Context for record remove operations passed from #handle_zone_to_name to | ||
1584 | * #handle_zone_to_name_it as closure | ||
1585 | */ | ||
1586 | struct ZoneToNameCtx | ||
1587 | { | ||
1588 | /** | ||
1589 | * Namestore client | ||
1590 | */ | ||
1591 | struct NamestoreClient *nc; | ||
1592 | |||
1593 | /** | ||
1594 | * Request id (to be used in the response to the client). | ||
1595 | */ | ||
1596 | uint32_t rid; | ||
1597 | |||
1598 | /** | ||
1599 | * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error. Note that | ||
1600 | * not finding a name for the zone still counts as a 'success' here, | ||
1601 | * as this field is about the success of executing the IPC protocol. | ||
1602 | */ | ||
1603 | int success; | ||
1604 | }; | ||
1605 | |||
1606 | |||
1607 | /** | ||
1608 | * Zone to name iterator | ||
1609 | * | ||
1610 | * @param cls struct ZoneToNameCtx * | ||
1611 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
1612 | * @param zone_key the zone key | ||
1613 | * @param name name | ||
1614 | * @param rd_count number of records in @a rd | ||
1615 | * @param rd record data | ||
1616 | */ | ||
1617 | static void | ||
1618 | handle_zone_to_name_it (void *cls, | ||
1619 | uint64_t seq, | ||
1620 | const struct GNUNET_IDENTITY_PrivateKey *zone_key, | ||
1621 | const char *name, | ||
1622 | unsigned int rd_count, | ||
1623 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1624 | { | ||
1625 | struct ZoneToNameCtx *ztn_ctx = cls; | ||
1626 | struct GNUNET_MQ_Envelope *env; | ||
1627 | struct ZoneToNameResponseMessage *ztnr_msg; | ||
1628 | int16_t res; | ||
1629 | size_t name_len; | ||
1630 | ssize_t rd_ser_len; | ||
1631 | size_t msg_size; | ||
1632 | char *name_tmp; | ||
1633 | char *rd_tmp; | ||
1634 | |||
1635 | GNUNET_assert (0 != seq); | ||
1636 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1637 | "Found result for zone-to-name lookup: `%s'\n", | ||
1638 | name); | ||
1639 | res = GNUNET_YES; | ||
1640 | name_len = (NULL == name) ? 0 : strlen (name) + 1; | ||
1641 | rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | ||
1642 | if (rd_ser_len < 0) | ||
1643 | { | ||
1644 | GNUNET_break (0); | ||
1645 | ztn_ctx->success = GNUNET_SYSERR; | ||
1646 | return; | ||
1647 | } | ||
1648 | msg_size = sizeof(struct ZoneToNameResponseMessage) + name_len + rd_ser_len; | ||
1649 | if (msg_size >= GNUNET_MAX_MESSAGE_SIZE) | ||
1650 | { | ||
1651 | GNUNET_break (0); | ||
1652 | ztn_ctx->success = GNUNET_SYSERR; | ||
1653 | return; | ||
1654 | } | ||
1655 | env = | ||
1656 | GNUNET_MQ_msg_extra (ztnr_msg, | ||
1657 | name_len + rd_ser_len, | ||
1658 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE); | ||
1659 | ztnr_msg->gns_header.header.size = htons (msg_size); | ||
1660 | ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid); | ||
1661 | ztnr_msg->res = htons (res); | ||
1662 | ztnr_msg->rd_len = htons (rd_ser_len); | ||
1663 | ztnr_msg->rd_count = htons (rd_count); | ||
1664 | ztnr_msg->name_len = htons (name_len); | ||
1665 | ztnr_msg->zone = *zone_key; | ||
1666 | name_tmp = (char *) &ztnr_msg[1]; | ||
1667 | GNUNET_memcpy (name_tmp, name, name_len); | ||
1668 | rd_tmp = &name_tmp[name_len]; | ||
1669 | GNUNET_assert ( | ||
1670 | rd_ser_len == | ||
1671 | GNUNET_GNSRECORD_records_serialize (rd_count, rd, rd_ser_len, rd_tmp)); | ||
1672 | ztn_ctx->success = GNUNET_OK; | ||
1673 | GNUNET_MQ_send (ztn_ctx->nc->mq, env); | ||
1674 | } | ||
1675 | |||
1676 | |||
1677 | /** | ||
1678 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message | ||
1679 | * | ||
1680 | * @param cls client client sending the message | ||
1681 | * @param ztn_msg message of type 'struct ZoneToNameMessage' | ||
1682 | */ | ||
1683 | static void | ||
1684 | handle_zone_to_name (void *cls, const struct ZoneToNameMessage *ztn_msg) | ||
1685 | { | ||
1686 | struct NamestoreClient *nc = cls; | ||
1687 | struct ZoneToNameCtx ztn_ctx; | ||
1688 | struct GNUNET_MQ_Envelope *env; | ||
1689 | struct ZoneToNameResponseMessage *ztnr_msg; | ||
1690 | |||
1691 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ZONE_TO_NAME message\n"); | ||
1692 | ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id); | ||
1693 | ztn_ctx.nc = nc; | ||
1694 | ztn_ctx.success = GNUNET_NO; | ||
1695 | if (GNUNET_SYSERR == GSN_database->zone_to_name (GSN_database->cls, | ||
1696 | &ztn_msg->zone, | ||
1697 | &ztn_msg->value_zone, | ||
1698 | &handle_zone_to_name_it, | ||
1699 | &ztn_ctx)) | ||
1700 | { | ||
1701 | /* internal error, hang up instead of signalling something | ||
1702 | that might be wrong */ | ||
1703 | GNUNET_break (0); | ||
1704 | GNUNET_SERVICE_client_drop (nc->client); | ||
1705 | return; | ||
1706 | } | ||
1707 | if (GNUNET_NO == ztn_ctx.success) | ||
1708 | { | ||
1709 | /* no result found, send empty response */ | ||
1710 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1711 | "Found no result for zone-to-name lookup.\n"); | ||
1712 | env = GNUNET_MQ_msg (ztnr_msg, | ||
1713 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE); | ||
1714 | ztnr_msg->gns_header.r_id = ztn_msg->gns_header.r_id; | ||
1715 | ztnr_msg->res = htons (GNUNET_NO); | ||
1716 | GNUNET_MQ_send (nc->mq, env); | ||
1717 | } | ||
1718 | GNUNET_SERVICE_client_continue (nc->client); | ||
1719 | } | ||
1720 | |||
1721 | |||
1722 | /** | ||
1723 | * Context for record remove operations passed from | ||
1724 | * #run_zone_iteration_round to #zone_iterate_proc as closure | ||
1725 | */ | ||
1726 | struct ZoneIterationProcResult | ||
1727 | { | ||
1728 | /** | ||
1729 | * The zone iteration handle | ||
1730 | */ | ||
1731 | struct ZoneIteration *zi; | ||
1732 | |||
1733 | /** | ||
1734 | * Number of results left to be returned in this iteration. | ||
1735 | */ | ||
1736 | uint64_t limit; | ||
1737 | }; | ||
1738 | |||
1739 | |||
1740 | /** | ||
1741 | * Process results for zone iteration from database | ||
1742 | * | ||
1743 | * @param cls struct ZoneIterationProcResult | ||
1744 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
1745 | * @param zone_key the zone key | ||
1746 | * @param name name | ||
1747 | * @param rd_count number of records for this name | ||
1748 | * @param rd record data | ||
1749 | */ | ||
1750 | static void | ||
1751 | zone_iterate_proc (void *cls, | ||
1752 | uint64_t seq, | ||
1753 | const struct GNUNET_IDENTITY_PrivateKey *zone_key, | ||
1754 | const char *name, | ||
1755 | unsigned int rd_count, | ||
1756 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1757 | { | ||
1758 | struct ZoneIterationProcResult *proc = cls; | ||
1759 | int do_refresh_block; | ||
1760 | |||
1761 | GNUNET_assert (0 != seq); | ||
1762 | if ((NULL == zone_key) && (NULL == name)) | ||
1763 | { | ||
1764 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n"); | ||
1765 | return; | ||
1766 | } | ||
1767 | if ((NULL == zone_key) || (NULL == name)) | ||
1768 | { | ||
1769 | /* what is this!? should never happen */ | ||
1770 | GNUNET_break (0); | ||
1771 | return; | ||
1772 | } | ||
1773 | if (0 == proc->limit) | ||
1774 | { | ||
1775 | /* what is this!? should never happen */ | ||
1776 | GNUNET_break (0); | ||
1777 | return; | ||
1778 | } | ||
1779 | proc->limit--; | ||
1780 | proc->zi->seq = seq; | ||
1781 | send_lookup_response (proc->zi->nc, | ||
1782 | proc->zi->request_id, | ||
1783 | zone_key, | ||
1784 | name, | ||
1785 | rd_count, | ||
1786 | rd); | ||
1787 | |||
1788 | |||
1789 | do_refresh_block = GNUNET_NO; | ||
1790 | for (unsigned int i = 0; i < rd_count; i++) | ||
1791 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) | ||
1792 | { | ||
1793 | do_refresh_block = GNUNET_YES; | ||
1794 | break; | ||
1795 | } | ||
1796 | if (GNUNET_YES == do_refresh_block) | ||
1797 | refresh_block (NULL, proc->zi, 0, zone_key, name, rd_count, rd); | ||
1798 | } | ||
1799 | |||
1800 | |||
1801 | /** | ||
1802 | * Perform the next round of the zone iteration. | ||
1803 | * | ||
1804 | * @param zi zone iterator to process | ||
1805 | * @param limit number of results to return in one pass | ||
1806 | */ | ||
1807 | static void | ||
1808 | run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit) | ||
1809 | { | ||
1810 | struct ZoneIterationProcResult proc; | ||
1811 | struct GNUNET_TIME_Absolute start; | ||
1812 | struct GNUNET_TIME_Relative duration; | ||
1813 | |||
1814 | memset (&proc, 0, sizeof(proc)); | ||
1815 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1816 | "Asked to return up to %llu records at position %llu\n", | ||
1817 | (unsigned long long) limit, | ||
1818 | (unsigned long long) zi->seq); | ||
1819 | proc.zi = zi; | ||
1820 | proc.limit = limit; | ||
1821 | start = GNUNET_TIME_absolute_get (); | ||
1822 | GNUNET_break (GNUNET_SYSERR != | ||
1823 | GSN_database->iterate_records (GSN_database->cls, | ||
1824 | (GNUNET_YES == GNUNET_is_zero ( | ||
1825 | &zi->zone)) | ||
1826 | ? NULL | ||
1827 | : &zi->zone, | ||
1828 | zi->seq, | ||
1829 | limit, | ||
1830 | &zone_iterate_proc, | ||
1831 | &proc)); | ||
1832 | duration = GNUNET_TIME_absolute_get_duration (start); | ||
1833 | duration = GNUNET_TIME_relative_divide (duration, limit - proc.limit); | ||
1834 | GNUNET_STATISTICS_set (statistics, | ||
1835 | "NAMESTORE iteration delay (μs/record)", | ||
1836 | duration.rel_value_us, | ||
1837 | GNUNET_NO); | ||
1838 | if (0 == proc.limit) | ||
1839 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1840 | "Returned %llu results, more results available\n", | ||
1841 | (unsigned long long) limit); | ||
1842 | zi->send_end = (0 != proc.limit); | ||
1843 | if (0 == zi->cache_ops) | ||
1844 | zone_iteration_done_client_continue (zi); | ||
1845 | } | ||
1846 | |||
1847 | |||
1848 | /** | ||
1849 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message | ||
1850 | * | ||
1851 | * @param cls the client sending the message | ||
1852 | * @param zis_msg message from the client | ||
1853 | */ | ||
1854 | static void | ||
1855 | handle_iteration_start (void *cls, | ||
1856 | const struct ZoneIterationStartMessage *zis_msg) | ||
1857 | { | ||
1858 | struct NamestoreClient *nc = cls; | ||
1859 | struct ZoneIteration *zi; | ||
1860 | |||
1861 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1862 | "Received ZONE_ITERATION_START message\n"); | ||
1863 | zi = GNUNET_new (struct ZoneIteration); | ||
1864 | zi->request_id = ntohl (zis_msg->gns_header.r_id); | ||
1865 | zi->offset = 0; | ||
1866 | zi->nc = nc; | ||
1867 | zi->zone = zis_msg->zone; | ||
1868 | |||
1869 | GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi); | ||
1870 | run_zone_iteration_round (zi, 1); | ||
1871 | } | ||
1872 | |||
1873 | |||
1874 | /** | ||
1875 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message | ||
1876 | * | ||
1877 | * @param cls the client sending the message | ||
1878 | * @param zis_msg message from the client | ||
1879 | */ | ||
1880 | static void | ||
1881 | handle_iteration_stop (void *cls, | ||
1882 | const struct ZoneIterationStopMessage *zis_msg) | ||
1883 | { | ||
1884 | struct NamestoreClient *nc = cls; | ||
1885 | struct ZoneIteration *zi; | ||
1886 | uint32_t rid; | ||
1887 | |||
1888 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1889 | "Received ZONE_ITERATION_STOP message\n"); | ||
1890 | rid = ntohl (zis_msg->gns_header.r_id); | ||
1891 | for (zi = nc->op_head; NULL != zi; zi = zi->next) | ||
1892 | if (zi->request_id == rid) | ||
1893 | break; | ||
1894 | if (NULL == zi) | ||
1895 | { | ||
1896 | GNUNET_break (0); | ||
1897 | GNUNET_SERVICE_client_drop (nc->client); | ||
1898 | return; | ||
1899 | } | ||
1900 | GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi); | ||
1901 | GNUNET_free (zi); | ||
1902 | GNUNET_SERVICE_client_continue (nc->client); | ||
1903 | } | ||
1904 | |||
1905 | |||
1906 | /** | ||
1907 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message | ||
1908 | * | ||
1909 | * @param cls the client sending the message | ||
1910 | * @param message message from the client | ||
1911 | */ | ||
1912 | static void | ||
1913 | handle_iteration_next (void *cls, | ||
1914 | const struct ZoneIterationNextMessage *zis_msg) | ||
1915 | { | ||
1916 | struct NamestoreClient *nc = cls; | ||
1917 | struct ZoneIteration *zi; | ||
1918 | uint32_t rid; | ||
1919 | uint64_t limit; | ||
1920 | |||
1921 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1922 | "Received ZONE_ITERATION_NEXT message\n"); | ||
1923 | GNUNET_STATISTICS_update (statistics, | ||
1924 | "Iteration NEXT messages received", | ||
1925 | 1, | ||
1926 | GNUNET_NO); | ||
1927 | rid = ntohl (zis_msg->gns_header.r_id); | ||
1928 | limit = GNUNET_ntohll (zis_msg->limit); | ||
1929 | for (zi = nc->op_head; NULL != zi; zi = zi->next) | ||
1930 | if (zi->request_id == rid) | ||
1931 | break; | ||
1932 | if (NULL == zi) | ||
1933 | { | ||
1934 | GNUNET_break (0); | ||
1935 | GNUNET_SERVICE_client_drop (nc->client); | ||
1936 | return; | ||
1937 | } | ||
1938 | run_zone_iteration_round (zi, limit); | ||
1939 | } | ||
1940 | |||
1941 | |||
1942 | /** | ||
1943 | * Function called when the monitor is ready for more data, and we | ||
1944 | * should thus unblock PUT operations that were blocked on the | ||
1945 | * monitor not being ready. | ||
1946 | */ | ||
1947 | static void | ||
1948 | monitor_unblock (struct ZoneMonitor *zm) | ||
1949 | { | ||
1950 | struct StoreActivity *sa = sa_head; | ||
1951 | |||
1952 | while ((NULL != sa) && (zm->limit > zm->iteration_cnt)) | ||
1953 | { | ||
1954 | struct StoreActivity *sn = sa->next; | ||
1955 | |||
1956 | if (sa->zm_pos == zm) | ||
1957 | continue_store_activity (sa); | ||
1958 | sa = sn; | ||
1959 | } | ||
1960 | if (zm->limit > zm->iteration_cnt) | ||
1961 | { | ||
1962 | zm->sa_waiting = GNUNET_NO; | ||
1963 | if (NULL != zm->sa_wait_warning) | ||
1964 | { | ||
1965 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
1966 | zm->sa_wait_warning = NULL; | ||
1967 | } | ||
1968 | } | ||
1969 | else if (GNUNET_YES == zm->sa_waiting) | ||
1970 | { | ||
1971 | zm->sa_waiting_start = GNUNET_TIME_absolute_get (); | ||
1972 | if (NULL != zm->sa_wait_warning) | ||
1973 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
1974 | zm->sa_wait_warning = | ||
1975 | GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
1976 | &warn_monitor_slow, | ||
1977 | zm); | ||
1978 | } | ||
1979 | } | ||
1980 | |||
1981 | |||
1982 | /** | ||
1983 | * Send 'sync' message to zone monitor, we're now in sync. | ||
1984 | * | ||
1985 | * @param zm monitor that is now in sync | ||
1986 | */ | ||
1987 | static void | ||
1988 | monitor_sync (struct ZoneMonitor *zm) | ||
1989 | { | ||
1990 | struct GNUNET_MQ_Envelope *env; | ||
1991 | struct GNUNET_MessageHeader *sync; | ||
1992 | |||
1993 | env = GNUNET_MQ_msg (sync, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC); | ||
1994 | GNUNET_MQ_send (zm->nc->mq, env); | ||
1995 | /* mark iteration done */ | ||
1996 | zm->in_first_iteration = GNUNET_NO; | ||
1997 | zm->iteration_cnt = 0; | ||
1998 | if ((zm->limit > 0) && (zm->sa_waiting)) | ||
1999 | monitor_unblock (zm); | ||
2000 | } | ||
2001 | |||
2002 | |||
2003 | /** | ||
2004 | * Obtain the next datum during the zone monitor's zone initial iteration. | ||
2005 | * | ||
2006 | * @param cls zone monitor that does its initial iteration | ||
2007 | */ | ||
2008 | static void | ||
2009 | monitor_iteration_next (void *cls); | ||
2010 | |||
2011 | |||
2012 | /** | ||
2013 | * A #GNUNET_NAMESTORE_RecordIterator for monitors. | ||
2014 | * | ||
2015 | * @param cls a 'struct ZoneMonitor *' with information about the monitor | ||
2016 | * @param seq sequence number of the record, MUST NOT BE ZERO | ||
2017 | * @param zone_key zone key of the zone | ||
2018 | * @param name name | ||
2019 | * @param rd_count number of records in @a rd | ||
2020 | * @param rd array of records | ||
2021 | */ | ||
2022 | static void | ||
2023 | monitor_iterate_cb (void *cls, | ||
2024 | uint64_t seq, | ||
2025 | const struct GNUNET_IDENTITY_PrivateKey *zone_key, | ||
2026 | const char *name, | ||
2027 | unsigned int rd_count, | ||
2028 | const struct GNUNET_GNSRECORD_Data *rd) | ||
2029 | { | ||
2030 | struct ZoneMonitor *zm = cls; | ||
2031 | |||
2032 | GNUNET_assert (0 != seq); | ||
2033 | zm->seq = seq; | ||
2034 | GNUNET_assert (NULL != name); | ||
2035 | GNUNET_STATISTICS_update (statistics, | ||
2036 | "Monitor notifications sent", | ||
2037 | 1, | ||
2038 | GNUNET_NO); | ||
2039 | zm->limit--; | ||
2040 | zm->iteration_cnt--; | ||
2041 | send_lookup_response (zm->nc, 0, zone_key, name, rd_count, rd); | ||
2042 | if ((0 == zm->iteration_cnt) && (0 != zm->limit)) | ||
2043 | { | ||
2044 | /* We are done with the current iteration batch, AND the | ||
2045 | client would right now accept more, so go again! */ | ||
2046 | GNUNET_assert (NULL == zm->task); | ||
2047 | zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm); | ||
2048 | } | ||
2049 | } | ||
2050 | |||
2051 | |||
2052 | /** | ||
2053 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message | ||
2054 | * | ||
2055 | * @param cls the client sending the message | ||
2056 | * @param zis_msg message from the client | ||
2057 | */ | ||
2058 | static void | ||
2059 | handle_monitor_start (void *cls, const struct ZoneMonitorStartMessage *zis_msg) | ||
2060 | { | ||
2061 | struct NamestoreClient *nc = cls; | ||
2062 | struct ZoneMonitor *zm; | ||
2063 | |||
2064 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ZONE_MONITOR_START message\n"); | ||
2065 | zm = GNUNET_new (struct ZoneMonitor); | ||
2066 | zm->nc = nc; | ||
2067 | zm->zone = zis_msg->zone; | ||
2068 | zm->limit = 1; | ||
2069 | zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first)); | ||
2070 | GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm); | ||
2071 | GNUNET_SERVICE_client_mark_monitor (nc->client); | ||
2072 | GNUNET_SERVICE_client_continue (nc->client); | ||
2073 | GNUNET_notification_context_add (monitor_nc, nc->mq); | ||
2074 | if (zm->in_first_iteration) | ||
2075 | zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm); | ||
2076 | else | ||
2077 | monitor_sync (zm); | ||
2078 | } | ||
2079 | |||
2080 | |||
2081 | /** | ||
2082 | * Obtain the next datum during the zone monitor's zone initial iteration. | ||
2083 | * | ||
2084 | * @param cls zone monitor that does its initial iteration | ||
2085 | */ | ||
2086 | static void | ||
2087 | monitor_iteration_next (void *cls) | ||
2088 | { | ||
2089 | struct ZoneMonitor *zm = cls; | ||
2090 | int ret; | ||
2091 | |||
2092 | zm->task = NULL; | ||
2093 | GNUNET_assert (0 == zm->iteration_cnt); | ||
2094 | if (zm->limit > 16) | ||
2095 | zm->iteration_cnt = zm->limit / 2; /* leave half for monitor events */ | ||
2096 | else | ||
2097 | zm->iteration_cnt = zm->limit; /* use it all */ | ||
2098 | ret = GSN_database->iterate_records (GSN_database->cls, | ||
2099 | (GNUNET_YES == GNUNET_is_zero ( | ||
2100 | &zm->zone)) | ||
2101 | ? NULL | ||
2102 | : &zm->zone, | ||
2103 | zm->seq, | ||
2104 | zm->iteration_cnt, | ||
2105 | &monitor_iterate_cb, | ||
2106 | zm); | ||
2107 | if (GNUNET_SYSERR == ret) | ||
2108 | { | ||
2109 | GNUNET_SERVICE_client_drop (zm->nc->client); | ||
2110 | return; | ||
2111 | } | ||
2112 | if (GNUNET_NO == ret) | ||
2113 | { | ||
2114 | /* empty zone */ | ||
2115 | monitor_sync (zm); | ||
2116 | return; | ||
2117 | } | ||
2118 | } | ||
2119 | |||
2120 | |||
2121 | /** | ||
2122 | * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT message | ||
2123 | * | ||
2124 | * @param cls the client sending the message | ||
2125 | * @param nm message from the client | ||
2126 | */ | ||
2127 | static void | ||
2128 | handle_monitor_next (void *cls, const struct ZoneMonitorNextMessage *nm) | ||
2129 | { | ||
2130 | struct NamestoreClient *nc = cls; | ||
2131 | struct ZoneMonitor *zm; | ||
2132 | uint64_t inc; | ||
2133 | |||
2134 | inc = GNUNET_ntohll (nm->limit); | ||
2135 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2136 | "Received ZONE_MONITOR_NEXT message with limit %llu\n", | ||
2137 | (unsigned long long) inc); | ||
2138 | for (zm = monitor_head; NULL != zm; zm = zm->next) | ||
2139 | if (zm->nc == nc) | ||
2140 | break; | ||
2141 | if (NULL == zm) | ||
2142 | { | ||
2143 | GNUNET_break (0); | ||
2144 | GNUNET_SERVICE_client_drop (nc->client); | ||
2145 | return; | ||
2146 | } | ||
2147 | GNUNET_SERVICE_client_continue (nc->client); | ||
2148 | if (zm->limit + inc < zm->limit) | ||
2149 | { | ||
2150 | GNUNET_break (0); | ||
2151 | GNUNET_SERVICE_client_drop (nc->client); | ||
2152 | return; | ||
2153 | } | ||
2154 | zm->limit += inc; | ||
2155 | if ((zm->in_first_iteration) && (zm->limit == inc)) | ||
2156 | { | ||
2157 | /* We are still iterating, and the previous iteration must | ||
2158 | have stopped due to the client's limit, so continue it! */ | ||
2159 | GNUNET_assert (NULL == zm->task); | ||
2160 | zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm); | ||
2161 | } | ||
2162 | GNUNET_assert (zm->iteration_cnt <= zm->limit); | ||
2163 | if ((zm->limit > zm->iteration_cnt) && (zm->sa_waiting)) | ||
2164 | { | ||
2165 | monitor_unblock (zm); | ||
2166 | } | ||
2167 | else if (GNUNET_YES == zm->sa_waiting) | ||
2168 | { | ||
2169 | if (NULL != zm->sa_wait_warning) | ||
2170 | GNUNET_SCHEDULER_cancel (zm->sa_wait_warning); | ||
2171 | zm->sa_waiting_start = GNUNET_TIME_absolute_get (); | ||
2172 | zm->sa_wait_warning = | ||
2173 | GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY, | ||
2174 | &warn_monitor_slow, | ||
2175 | zm); | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2179 | |||
2180 | /** | ||
2181 | * Process namestore requests. | ||
2182 | * | ||
2183 | * @param cls closure | ||
2184 | * @param cfg configuration to use | ||
2185 | * @param service the initialized service | ||
2186 | */ | ||
2187 | static void | ||
2188 | run (void *cls, | ||
2189 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
2190 | struct GNUNET_SERVICE_Handle *service) | ||
2191 | { | ||
2192 | char *database; | ||
2193 | |||
2194 | (void) cls; | ||
2195 | (void) service; | ||
2196 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n"); | ||
2197 | cache_keys = | ||
2198 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "namestore", "CACHE_KEYS"); | ||
2199 | disable_namecache = | ||
2200 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "namecache", "DISABLE"); | ||
2201 | GSN_cfg = cfg; | ||
2202 | monitor_nc = GNUNET_notification_context_create (1); | ||
2203 | if (GNUNET_YES != disable_namecache) | ||
2204 | { | ||
2205 | namecache = GNUNET_NAMECACHE_connect (cfg); | ||
2206 | GNUNET_assert (NULL != namecache); | ||
2207 | } | ||
2208 | /* Loading database plugin */ | ||
2209 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, | ||
2210 | "namestore", | ||
2211 | "database", | ||
2212 | &database)) | ||
2213 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); | ||
2214 | |||
2215 | GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database); | ||
2216 | GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg); | ||
2217 | GNUNET_free (database); | ||
2218 | statistics = GNUNET_STATISTICS_create ("namestore", cfg); | ||
2219 | GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL); | ||
2220 | if (NULL == GSN_database) | ||
2221 | { | ||
2222 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2223 | "Could not load database backend `%s'\n", | ||
2224 | db_lib_name); | ||
2225 | GNUNET_SCHEDULER_shutdown (); | ||
2226 | return; | ||
2227 | } | ||
2228 | } | ||
2229 | |||
2230 | |||
2231 | /** | ||
2232 | * Define "main" method using service macro. | ||
2233 | */ | ||
2234 | GNUNET_SERVICE_MAIN ( | ||
2235 | "namestore", | ||
2236 | GNUNET_SERVICE_OPTION_NONE, | ||
2237 | &run, | ||
2238 | &client_connect_cb, | ||
2239 | &client_disconnect_cb, | ||
2240 | NULL, | ||
2241 | GNUNET_MQ_hd_var_size (record_store, | ||
2242 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE, | ||
2243 | struct RecordStoreMessage, | ||
2244 | NULL), | ||
2245 | GNUNET_MQ_hd_var_size (record_lookup, | ||
2246 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP, | ||
2247 | struct LabelLookupMessage, | ||
2248 | NULL), | ||
2249 | GNUNET_MQ_hd_fixed_size (zone_to_name, | ||
2250 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, | ||
2251 | struct ZoneToNameMessage, | ||
2252 | NULL), | ||
2253 | GNUNET_MQ_hd_fixed_size (iteration_start, | ||
2254 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, | ||
2255 | struct ZoneIterationStartMessage, | ||
2256 | NULL), | ||
2257 | GNUNET_MQ_hd_fixed_size (iteration_next, | ||
2258 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, | ||
2259 | struct ZoneIterationNextMessage, | ||
2260 | NULL), | ||
2261 | GNUNET_MQ_hd_fixed_size (iteration_stop, | ||
2262 | GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, | ||
2263 | struct ZoneIterationStopMessage, | ||
2264 | NULL), | ||
2265 | GNUNET_MQ_hd_fixed_size (monitor_start, | ||
2266 | GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START, | ||
2267 | struct ZoneMonitorStartMessage, | ||
2268 | NULL), | ||
2269 | GNUNET_MQ_hd_fixed_size (monitor_next, | ||
2270 | GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT, | ||
2271 | struct ZoneMonitorNextMessage, | ||
2272 | NULL), | ||
2273 | GNUNET_MQ_handler_end ()); | ||
2274 | |||
2275 | |||
2276 | /* end of gnunet-service-namestore.c */ | ||