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.
17 * @file namecache/gnunet-service-namecache.c
18 * @brief namecache for the GNUnet naming system
19 * @author Matthias Wachs
20 * @author Christian Grothoff
23 #include "gnunet_util_lib.h"
24 #include "gnunet_dnsparser_lib.h"
25 #include "gnunet_namecache_service.h"
26 #include "gnunet_namecache_plugin.h"
27 #include "gnunet_signatures.h"
28 #include "namecache.h"
30 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
36 struct NamecacheClient
42 struct GNUNET_SERVICE_Client *client;
45 * The message queue to talk to @e client.
47 struct GNUNET_MQ_Handle *mq;
53 * Configuration handle.
55 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
60 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
63 * Name of the database plugin
65 static char *db_lib_name;
69 * Task run during shutdown.
74 cleanup_task (void *cls)
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "Stopping namecache service\n");
79 GNUNET_PLUGIN_unload (db_lib_name,
81 GNUNET_free (db_lib_name);
87 * Called whenever a client is disconnected.
88 * Frees our resources associated with that client.
91 * @param client identification of the client
92 * @param app_ctx the `struct NamecacheClient` for this @a client
95 client_disconnect_cb (void *cls,
96 struct GNUNET_SERVICE_Client *client,
99 struct NamecacheClient *nc = app_ctx;
101 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
102 "Client %p disconnected\n",
109 * Add a client to our list of active clients.
112 * @param client client to add
113 * @param mq queue to talk to @a client
114 * @return internal namecache client structure for this client
117 client_connect_cb (void *cls,
118 struct GNUNET_SERVICE_Client *client,
119 struct GNUNET_MQ_Handle *mq)
121 struct NamecacheClient *nc;
123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
124 "Client %p connected\n",
126 nc = GNUNET_new (struct NamecacheClient);
134 * Context for name lookups passed from #handle_lookup_block to
135 * #handle_lookup_block_it as closure
137 struct LookupBlockContext
140 * The client to send the response to
142 struct NamecacheClient *nc;
145 * Operation id for the name lookup
153 * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
155 * @param cls a `struct LookupNameContext *` with information about the request
156 * @param block the block
159 handle_lookup_block_it (void *cls,
160 const struct GNUNET_GNSRECORD_Block *block)
162 struct LookupBlockContext *lnc = cls;
163 struct GNUNET_MQ_Envelope *env;
164 struct LookupBlockResponseMessage *r;
167 esize = ntohl (block->purpose.size)
168 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
169 - sizeof (struct GNUNET_TIME_AbsoluteNBO);
170 env = GNUNET_MQ_msg_extra (r,
172 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
173 r->gns_header.r_id = htonl (lnc->request_id);
174 r->expire = block->expiration_time;
175 r->signature = block->signature;
176 r->derived_key = block->derived_key;
177 GNUNET_memcpy (&r[1],
180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181 "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message with expiration time %s\n",
182 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (r->expire)));
183 GNUNET_MQ_send (lnc->nc->mq,
189 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
191 * @param cls a `struct NamecacheClient *`
192 * @param the inbound message
195 handle_lookup_block (void *cls,
196 const struct LookupBlockMessage *ln_msg)
198 struct NamecacheClient *nc = cls;
199 struct GNUNET_MQ_Envelope *env;
200 struct LookupBlockContext lnc;
201 struct LookupBlockResponseMessage *zir_end;
204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205 "Received NAMECACHE_LOOKUP_BLOCK message\n");
207 lnc.request_id = ntohl (ln_msg->gns_header.r_id);
210 (ret = GSN_database->lookup_block (GSN_database->cls,
212 &handle_lookup_block_it,
215 /* internal error (in database plugin); might be best to just hang up on
216 plugin rather than to signal that there are 'no' results, which
217 might also be false... */
219 GNUNET_SERVICE_client_drop (nc->client);
224 /* no records match at all, generate empty response */
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226 "Sending empty NAMECACHE_LOOKUP_BLOCK_RESPONSE message\n");
227 env = GNUNET_MQ_msg (zir_end,
228 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
229 zir_end->gns_header.r_id = ln_msg->gns_header.r_id;
230 GNUNET_MQ_send (nc->mq,
233 GNUNET_SERVICE_client_continue (nc->client);
238 * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
240 * @param cls our `struct NamecacheClient`
241 * @param rp_msg message to process
242 * @return #GNUNET_OK (always fine)
245 check_block_cache (void *cls,
246 const struct BlockCacheMessage *rp_msg)
253 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
255 * @param cls our `struct NamecacheClient`
256 * @param rp_msg message to process
259 handle_block_cache (void *cls,
260 const struct BlockCacheMessage *rp_msg)
262 struct NamecacheClient *nc = cls;
263 struct GNUNET_MQ_Envelope *env;
264 struct BlockCacheResponseMessage *rpr_msg;
265 struct GNUNET_GNSRECORD_Block *block;
269 esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
270 block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + esize);
271 block->signature = rp_msg->signature;
272 block->derived_key = rp_msg->derived_key;
273 block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
274 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
276 block->expiration_time = rp_msg->expire;
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Received NAMECACHE_BLOCK_CACHE message with expiration time %s\n",
279 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (block->expiration_time)));
280 GNUNET_memcpy (&block[1],
283 res = GSN_database->cache_block (GSN_database->cls,
286 env = GNUNET_MQ_msg (rpr_msg,
287 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
288 rpr_msg->gns_header.r_id = rp_msg->gns_header.r_id;
289 rpr_msg->op_result = htonl (res);
290 GNUNET_MQ_send (nc->mq,
292 GNUNET_SERVICE_client_continue (nc->client);
297 * Process namecache requests.
300 * @param cfg configuration to use
301 * @param service the initialized service
305 const struct GNUNET_CONFIGURATION_Handle *cfg,
306 struct GNUNET_SERVICE_Handle *service)
310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
311 "Starting namecache service\n");
314 /* Loading database plugin */
316 GNUNET_CONFIGURATION_get_value_string (cfg,
320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
321 "No database backend configured\n");
323 GNUNET_asprintf (&db_lib_name,
324 "libgnunet_plugin_namecache_%s",
326 GSN_database = GNUNET_PLUGIN_load (db_lib_name,
328 GNUNET_free (database);
329 if (NULL == GSN_database)
331 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
332 "Could not load database backend `%s'\n",
334 GNUNET_SCHEDULER_add_now (&cleanup_task,
339 /* Configuring server handles */
340 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
346 * Define "main" method using service macro.
350 GNUNET_SERVICE_OPTION_NONE,
353 &client_disconnect_cb,
355 GNUNET_MQ_hd_fixed_size (lookup_block,
356 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
357 struct LookupBlockMessage,
359 GNUNET_MQ_hd_var_size (block_cache,
360 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
361 struct BlockCacheMessage,
363 GNUNET_MQ_handler_end ());
366 /* end of gnunet-service-namecache.c */