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
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
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_namecache_service.h"
31 #include "gnunet_namecache_plugin.h"
32 #include "gnunet_signatures.h"
33 #include "namecache.h"
35 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
41 struct NamecacheClient
47 struct GNUNET_SERVICE_Client *client;
50 * The message queue to talk to @e client.
52 struct GNUNET_MQ_Handle *mq;
58 * Configuration handle.
60 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
65 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
68 * Name of the database plugin
70 static char *db_lib_name;
74 * Task run during shutdown.
79 cleanup_task (void *cls)
81 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
82 "Stopping namecache service\n");
84 GNUNET_PLUGIN_unload (db_lib_name,
86 GNUNET_free (db_lib_name);
92 * Called whenever a client is disconnected.
93 * Frees our resources associated with that client.
96 * @param client identification of the client
97 * @param app_ctx the `struct NamecacheClient` for this @a client
100 client_disconnect_cb (void *cls,
101 struct GNUNET_SERVICE_Client *client,
104 struct NamecacheClient *nc = app_ctx;
106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
107 "Client %p disconnected\n",
114 * Add a client to our list of active clients.
117 * @param client client to add
118 * @param mq queue to talk to @a client
119 * @return internal namecache client structure for this client
122 client_connect_cb (void *cls,
123 struct GNUNET_SERVICE_Client *client,
124 struct GNUNET_MQ_Handle *mq)
126 struct NamecacheClient *nc;
128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
129 "Client %p connected\n",
131 nc = GNUNET_new (struct NamecacheClient);
139 * Context for name lookups passed from #handle_lookup_block to
140 * #handle_lookup_block_it as closure
142 struct LookupBlockContext
145 * The client to send the response to
147 struct NamecacheClient *nc;
150 * Operation id for the name lookup
158 * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
160 * @param cls a `struct LookupNameContext *` with information about the request
161 * @param block the block
164 handle_lookup_block_it (void *cls,
165 const struct GNUNET_GNSRECORD_Block *block)
167 struct LookupBlockContext *lnc = cls;
168 struct GNUNET_MQ_Envelope *env;
169 struct LookupBlockResponseMessage *r;
172 esize = ntohl (block->purpose.size)
173 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
174 - sizeof (struct GNUNET_TIME_AbsoluteNBO);
175 env = GNUNET_MQ_msg_extra (r,
177 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
178 r->gns_header.r_id = htonl (lnc->request_id);
179 r->expire = block->expiration_time;
180 r->signature = block->signature;
181 r->derived_key = block->derived_key;
182 GNUNET_memcpy (&r[1],
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186 "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message with expiration time %s\n",
187 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (r->expire)));
188 GNUNET_MQ_send (lnc->nc->mq,
194 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
196 * @param cls a `struct NamecacheClient *`
197 * @param the inbound message
200 handle_lookup_block (void *cls,
201 const struct LookupBlockMessage *ln_msg)
203 struct NamecacheClient *nc = cls;
204 struct GNUNET_MQ_Envelope *env;
205 struct LookupBlockContext lnc;
206 struct LookupBlockResponseMessage *zir_end;
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210 "Received NAMECACHE_LOOKUP_BLOCK message\n");
212 lnc.request_id = ntohl (ln_msg->gns_header.r_id);
215 (ret = GSN_database->lookup_block (GSN_database->cls,
217 &handle_lookup_block_it,
220 /* internal error (in database plugin); might be best to just hang up on
221 plugin rather than to signal that there are 'no' results, which
222 might also be false... */
224 GNUNET_SERVICE_client_drop (nc->client);
229 /* no records match at all, generate empty response */
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Sending empty NAMECACHE_LOOKUP_BLOCK_RESPONSE message\n");
232 env = GNUNET_MQ_msg (zir_end,
233 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
234 zir_end->gns_header.r_id = ln_msg->gns_header.r_id;
235 GNUNET_MQ_send (nc->mq,
238 GNUNET_SERVICE_client_continue (nc->client);
243 * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
245 * @param cls our `struct NamecacheClient`
246 * @param rp_msg message to process
247 * @return #GNUNET_OK (always fine)
250 check_block_cache (void *cls,
251 const struct BlockCacheMessage *rp_msg)
258 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
260 * @param cls our `struct NamecacheClient`
261 * @param rp_msg message to process
264 handle_block_cache (void *cls,
265 const struct BlockCacheMessage *rp_msg)
267 struct NamecacheClient *nc = cls;
268 struct GNUNET_MQ_Envelope *env;
269 struct BlockCacheResponseMessage *rpr_msg;
270 struct GNUNET_GNSRECORD_Block *block;
274 esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
275 block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + esize);
276 block->signature = rp_msg->signature;
277 block->derived_key = rp_msg->derived_key;
278 block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
279 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
281 block->expiration_time = rp_msg->expire;
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Received NAMECACHE_BLOCK_CACHE message with expiration time %s\n",
284 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (block->expiration_time)));
285 GNUNET_memcpy (&block[1],
288 res = GSN_database->cache_block (GSN_database->cls,
291 env = GNUNET_MQ_msg (rpr_msg,
292 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
293 rpr_msg->gns_header.r_id = rp_msg->gns_header.r_id;
294 rpr_msg->op_result = htonl (res);
295 GNUNET_MQ_send (nc->mq,
297 GNUNET_SERVICE_client_continue (nc->client);
302 * Process namecache requests.
305 * @param cfg configuration to use
306 * @param service the initialized service
310 const struct GNUNET_CONFIGURATION_Handle *cfg,
311 struct GNUNET_SERVICE_Handle *service)
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Starting namecache service\n");
319 /* Loading database plugin */
321 GNUNET_CONFIGURATION_get_value_string (cfg,
325 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
326 "No database backend configured\n");
328 GNUNET_asprintf (&db_lib_name,
329 "libgnunet_plugin_namecache_%s",
331 GSN_database = GNUNET_PLUGIN_load (db_lib_name,
333 GNUNET_free (database);
334 if (NULL == GSN_database)
336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
337 "Could not load database backend `%s'\n",
339 GNUNET_SCHEDULER_add_now (&cleanup_task,
344 /* Configuring server handles */
345 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
351 * Define "main" method using service macro.
355 GNUNET_SERVICE_OPTION_NONE,
358 &client_disconnect_cb,
360 GNUNET_MQ_hd_fixed_size (lookup_block,
361 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
362 struct LookupBlockMessage,
364 GNUNET_MQ_hd_var_size (block_cache,
365 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
366 struct BlockCacheMessage,
368 GNUNET_MQ_handler_end ());
371 /* end of gnunet-service-namecache.c */