2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file namecache/gnunet-service-namecache.c
23 * @brief namecache for the GNUnet naming system
24 * @author Matthias Wachs
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dnsparser_lib.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet_namecache_service.h"
32 #include "gnunet_namecache_plugin.h"
33 #include "gnunet_signatures.h"
34 #include "namecache.h"
36 #define LOG_STRERROR_FILE(kind, syscall, \
37 filename) GNUNET_log_from_strerror_file (kind, "util", \
45 struct NamecacheClient
50 struct GNUNET_SERVICE_Client *client;
53 * The message queue to talk to @e client.
55 struct GNUNET_MQ_Handle *mq;
60 * Configuration handle.
62 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
65 * Handle to the statistics service
67 static struct GNUNET_STATISTICS_Handle *statistics;
72 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
75 * Name of the database plugin
77 static char *db_lib_name;
81 * Task run during shutdown.
86 cleanup_task (void *cls)
88 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
89 "Stopping namecache service\n");
91 GNUNET_PLUGIN_unload (db_lib_name,
93 GNUNET_free (db_lib_name);
95 if (NULL != statistics)
97 GNUNET_STATISTICS_destroy (statistics,
105 * Called whenever a client is disconnected.
106 * Frees our resources associated with that client.
109 * @param client identification of the client
110 * @param app_ctx the `struct NamecacheClient` for this @a client
113 client_disconnect_cb (void *cls,
114 struct GNUNET_SERVICE_Client *client,
117 struct NamecacheClient *nc = app_ctx;
119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
120 "Client %p disconnected\n",
127 * Add a client to our list of active clients.
130 * @param client client to add
131 * @param mq queue to talk to @a client
132 * @return internal namecache client structure for this client
135 client_connect_cb (void *cls,
136 struct GNUNET_SERVICE_Client *client,
137 struct GNUNET_MQ_Handle *mq)
139 struct NamecacheClient *nc;
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Client %p connected\n",
144 nc = GNUNET_new (struct NamecacheClient);
152 * Context for name lookups passed from #handle_lookup_block to
153 * #handle_lookup_block_it as closure
155 struct LookupBlockContext
158 * The client to send the response to
160 struct NamecacheClient *nc;
163 * Operation id for the name lookup
175 * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
177 * @param cls a `struct LookupNameContext *` with information about the request
178 * @param block the block
181 handle_lookup_block_it (void *cls,
182 const struct GNUNET_GNSRECORD_Block *block)
184 struct LookupBlockContext *lnc = cls;
185 struct GNUNET_MQ_Envelope *env;
186 struct LookupBlockResponseMessage *r;
190 bsize = ntohl (block->purpose.size);
192 (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof(struct
193 GNUNET_TIME_AbsoluteNBO)))
195 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
197 lnc->status = GNUNET_SYSERR;
200 esize = ntohl (block->purpose.size)
201 - sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
202 - sizeof(struct GNUNET_TIME_AbsoluteNBO);
203 env = GNUNET_MQ_msg_extra (r,
205 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
206 r->gns_header.r_id = htonl (lnc->request_id);
207 r->expire = block->expiration_time;
208 r->signature = block->signature;
209 r->derived_key = block->derived_key;
210 GNUNET_memcpy (&r[1],
213 GNUNET_STATISTICS_update (statistics,
214 "blocks found in cache",
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218 "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message with expiration time %s\n",
219 GNUNET_STRINGS_absolute_time_to_string (
220 GNUNET_TIME_absolute_ntoh (r->expire)));
221 GNUNET_MQ_send (lnc->nc->mq,
227 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
229 * @param cls a `struct NamecacheClient *`
230 * @param the inbound message
233 handle_lookup_block (void *cls,
234 const struct LookupBlockMessage *ln_msg)
236 struct NamecacheClient *nc = cls;
237 struct GNUNET_MQ_Envelope *env;
238 struct LookupBlockContext lnc;
239 struct LookupBlockResponseMessage *zir_end;
242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243 "Received NAMECACHE_LOOKUP_BLOCK message\n");
244 GNUNET_STATISTICS_update (statistics,
248 lnc.request_id = ntohl (ln_msg->gns_header.r_id);
250 lnc.status = GNUNET_OK;
252 (ret = GSN_database->lookup_block (GSN_database->cls,
254 &handle_lookup_block_it,
257 /* internal error (in database plugin); might be best to just hang up on
258 plugin rather than to signal that there are 'no' results, which
259 might also be false... */
261 GNUNET_SERVICE_client_drop (nc->client);
264 if ((0 == ret) || (GNUNET_SYSERR == lnc.status))
266 /* no records match at all, generate empty response */
267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268 "Sending empty NAMECACHE_LOOKUP_BLOCK_RESPONSE message\n");
269 env = GNUNET_MQ_msg (zir_end,
270 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
271 zir_end->gns_header.r_id = ln_msg->gns_header.r_id;
272 GNUNET_MQ_send (nc->mq,
275 GNUNET_SERVICE_client_continue (nc->client);
280 * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
282 * @param cls our `struct NamecacheClient`
283 * @param rp_msg message to process
284 * @return #GNUNET_OK (always fine)
287 check_block_cache (void *cls,
288 const struct BlockCacheMessage *rp_msg)
295 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
297 * @param cls our `struct NamecacheClient`
298 * @param rp_msg message to process
301 handle_block_cache (void *cls,
302 const struct BlockCacheMessage *rp_msg)
304 struct NamecacheClient *nc = cls;
305 struct GNUNET_MQ_Envelope *env;
306 struct BlockCacheResponseMessage *rpr_msg;
307 struct GNUNET_GNSRECORD_Block *block;
311 GNUNET_STATISTICS_update (statistics,
315 esize = ntohs (rp_msg->gns_header.header.size) - sizeof(struct
317 block = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Block) + esize);
318 block->signature = rp_msg->signature;
319 block->derived_key = rp_msg->derived_key;
320 block->purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
321 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
323 block->expiration_time = rp_msg->expire;
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
325 "Received NAMECACHE_BLOCK_CACHE message with expiration time %s\n",
326 GNUNET_STRINGS_absolute_time_to_string (
327 GNUNET_TIME_absolute_ntoh (block->expiration_time)));
328 GNUNET_memcpy (&block[1],
331 res = GSN_database->cache_block (GSN_database->cls,
334 env = GNUNET_MQ_msg (rpr_msg,
335 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
336 rpr_msg->gns_header.r_id = rp_msg->gns_header.r_id;
337 rpr_msg->op_result = htonl (res);
338 GNUNET_MQ_send (nc->mq,
340 GNUNET_SERVICE_client_continue (nc->client);
345 * Process namecache requests.
348 * @param cfg configuration to use
349 * @param service the initialized service
353 const struct GNUNET_CONFIGURATION_Handle *cfg,
354 struct GNUNET_SERVICE_Handle *service)
358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
359 "Starting namecache service\n");
362 /* Loading database plugin */
364 GNUNET_CONFIGURATION_get_value_string (cfg,
368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
369 "No database backend configured\n");
371 GNUNET_asprintf (&db_lib_name,
372 "libgnunet_plugin_namecache_%s",
374 GSN_database = GNUNET_PLUGIN_load (db_lib_name,
376 GNUNET_free (database);
377 if (NULL == GSN_database)
379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
380 "Could not load database backend `%s'\n",
382 GNUNET_SCHEDULER_add_now (&cleanup_task,
386 statistics = GNUNET_STATISTICS_create ("namecache",
389 /* Configuring server handles */
390 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
396 * Define "main" method using service macro.
400 GNUNET_SERVICE_OPTION_NONE,
403 &client_disconnect_cb,
405 GNUNET_MQ_hd_fixed_size (lookup_block,
406 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
407 struct LookupBlockMessage,
409 GNUNET_MQ_hd_var_size (block_cache,
410 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
411 struct BlockCacheMessage,
413 GNUNET_MQ_handler_end ());
416 /* end of gnunet-service-namecache.c */