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/>.
20 * @file namecache/gnunet-service-namecache.c
21 * @brief namecache for the GNUnet naming system
22 * @author Matthias Wachs
23 * @author Christian Grothoff
26 #include "gnunet_util_lib.h"
27 #include "gnunet_dnsparser_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_namecache_service.h"
30 #include "gnunet_namecache_plugin.h"
31 #include "gnunet_signatures.h"
32 #include "namecache.h"
34 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
40 struct NamecacheClient
46 struct GNUNET_SERVICE_Client *client;
49 * The message queue to talk to @e client.
51 struct GNUNET_MQ_Handle *mq;
57 * Configuration handle.
59 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
62 * Handle to the statistics service
64 static struct GNUNET_STATISTICS_Handle *statistics;
69 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
72 * Name of the database plugin
74 static char *db_lib_name;
78 * Task run during shutdown.
83 cleanup_task (void *cls)
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Stopping namecache service\n");
88 GNUNET_PLUGIN_unload (db_lib_name,
90 GNUNET_free (db_lib_name);
92 if (NULL != statistics)
94 GNUNET_STATISTICS_destroy (statistics,
102 * Called whenever a client is disconnected.
103 * Frees our resources associated with that client.
106 * @param client identification of the client
107 * @param app_ctx the `struct NamecacheClient` for this @a client
110 client_disconnect_cb (void *cls,
111 struct GNUNET_SERVICE_Client *client,
114 struct NamecacheClient *nc = app_ctx;
116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
117 "Client %p disconnected\n",
124 * Add a client to our list of active clients.
127 * @param client client to add
128 * @param mq queue to talk to @a client
129 * @return internal namecache client structure for this client
132 client_connect_cb (void *cls,
133 struct GNUNET_SERVICE_Client *client,
134 struct GNUNET_MQ_Handle *mq)
136 struct NamecacheClient *nc;
138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
139 "Client %p connected\n",
141 nc = GNUNET_new (struct NamecacheClient);
149 * Context for name lookups passed from #handle_lookup_block to
150 * #handle_lookup_block_it as closure
152 struct LookupBlockContext
155 * The client to send the response to
157 struct NamecacheClient *nc;
160 * Operation id for the name lookup
172 * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
174 * @param cls a `struct LookupNameContext *` with information about the request
175 * @param block the block
178 handle_lookup_block_it (void *cls,
179 const struct GNUNET_GNSRECORD_Block *block)
181 struct LookupBlockContext *lnc = cls;
182 struct GNUNET_MQ_Envelope *env;
183 struct LookupBlockResponseMessage *r;
187 bsize = ntohl (block->purpose.size);
189 (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO)))
191 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
193 lnc->status = GNUNET_SYSERR;
196 esize = ntohl (block->purpose.size)
197 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
198 - sizeof (struct GNUNET_TIME_AbsoluteNBO);
199 env = GNUNET_MQ_msg_extra (r,
201 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
202 r->gns_header.r_id = htonl (lnc->request_id);
203 r->expire = block->expiration_time;
204 r->signature = block->signature;
205 r->derived_key = block->derived_key;
206 GNUNET_memcpy (&r[1],
209 GNUNET_STATISTICS_update (statistics,
210 "blocks found in cache",
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message with expiration time %s\n",
215 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (r->expire)));
216 GNUNET_MQ_send (lnc->nc->mq,
222 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
224 * @param cls a `struct NamecacheClient *`
225 * @param the inbound message
228 handle_lookup_block (void *cls,
229 const struct LookupBlockMessage *ln_msg)
231 struct NamecacheClient *nc = cls;
232 struct GNUNET_MQ_Envelope *env;
233 struct LookupBlockContext lnc;
234 struct LookupBlockResponseMessage *zir_end;
237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
238 "Received NAMECACHE_LOOKUP_BLOCK message\n");
239 GNUNET_STATISTICS_update (statistics,
243 lnc.request_id = ntohl (ln_msg->gns_header.r_id);
245 lnc.status = GNUNET_OK;
247 (ret = GSN_database->lookup_block (GSN_database->cls,
249 &handle_lookup_block_it,
252 /* internal error (in database plugin); might be best to just hang up on
253 plugin rather than to signal that there are 'no' results, which
254 might also be false... */
256 GNUNET_SERVICE_client_drop (nc->client);
259 if ((0 == ret) || (GNUNET_SYSERR == lnc.status))
261 /* no records match at all, generate empty response */
262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263 "Sending empty NAMECACHE_LOOKUP_BLOCK_RESPONSE message\n");
264 env = GNUNET_MQ_msg (zir_end,
265 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
266 zir_end->gns_header.r_id = ln_msg->gns_header.r_id;
267 GNUNET_MQ_send (nc->mq,
270 GNUNET_SERVICE_client_continue (nc->client);
275 * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
277 * @param cls our `struct NamecacheClient`
278 * @param rp_msg message to process
279 * @return #GNUNET_OK (always fine)
282 check_block_cache (void *cls,
283 const struct BlockCacheMessage *rp_msg)
290 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
292 * @param cls our `struct NamecacheClient`
293 * @param rp_msg message to process
296 handle_block_cache (void *cls,
297 const struct BlockCacheMessage *rp_msg)
299 struct NamecacheClient *nc = cls;
300 struct GNUNET_MQ_Envelope *env;
301 struct BlockCacheResponseMessage *rpr_msg;
302 struct GNUNET_GNSRECORD_Block *block;
306 GNUNET_STATISTICS_update (statistics,
310 esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
311 block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + esize);
312 block->signature = rp_msg->signature;
313 block->derived_key = rp_msg->derived_key;
314 block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
315 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
317 block->expiration_time = rp_msg->expire;
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319 "Received NAMECACHE_BLOCK_CACHE message with expiration time %s\n",
320 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (block->expiration_time)));
321 GNUNET_memcpy (&block[1],
324 res = GSN_database->cache_block (GSN_database->cls,
327 env = GNUNET_MQ_msg (rpr_msg,
328 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
329 rpr_msg->gns_header.r_id = rp_msg->gns_header.r_id;
330 rpr_msg->op_result = htonl (res);
331 GNUNET_MQ_send (nc->mq,
333 GNUNET_SERVICE_client_continue (nc->client);
338 * Process namecache requests.
341 * @param cfg configuration to use
342 * @param service the initialized service
346 const struct GNUNET_CONFIGURATION_Handle *cfg,
347 struct GNUNET_SERVICE_Handle *service)
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Starting namecache service\n");
355 /* Loading database plugin */
357 GNUNET_CONFIGURATION_get_value_string (cfg,
361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
362 "No database backend configured\n");
364 GNUNET_asprintf (&db_lib_name,
365 "libgnunet_plugin_namecache_%s",
367 GSN_database = GNUNET_PLUGIN_load (db_lib_name,
369 GNUNET_free (database);
370 if (NULL == GSN_database)
372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
373 "Could not load database backend `%s'\n",
375 GNUNET_SCHEDULER_add_now (&cleanup_task,
379 statistics = GNUNET_STATISTICS_create ("namecache",
382 /* Configuring server handles */
383 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
389 * Define "main" method using service macro.
393 GNUNET_SERVICE_OPTION_NONE,
396 &client_disconnect_cb,
398 GNUNET_MQ_hd_fixed_size (lookup_block,
399 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
400 struct LookupBlockMessage,
402 GNUNET_MQ_hd_var_size (block_cache,
403 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
404 struct BlockCacheMessage,
406 GNUNET_MQ_handler_end ());
409 /* end of gnunet-service-namecache.c */