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 NamecacheClient
50 * Next element in the DLL
52 struct NamecacheClient *next;
55 * Previous element in the DLL
57 struct NamecacheClient *prev;
62 struct GNUNET_SERVER_Client *client;
68 * Configuration handle.
70 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
75 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
78 * Name of the database plugin
80 static char *db_lib_name;
83 * Our notification context.
85 static struct GNUNET_SERVER_NotificationContext *snc;
88 * Head of the Client DLL
90 static struct NamecacheClient *client_head;
93 * Tail of the Client DLL
95 static struct NamecacheClient *client_tail;
98 * Notification context shared by all monitors.
100 static struct GNUNET_SERVER_NotificationContext *monitor_nc;
105 * Task run during shutdown.
110 cleanup_task (void *cls)
112 struct NamecacheClient *nc;
114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
115 "Stopping namecache service\n");
118 GNUNET_SERVER_notification_context_destroy (snc);
121 while (NULL != (nc = client_head))
123 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
124 GNUNET_SERVER_client_set_user_context (nc->client, NULL);
127 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
128 GNUNET_free (db_lib_name);
130 if (NULL != monitor_nc)
132 GNUNET_SERVER_notification_context_destroy (monitor_nc);
139 * Called whenever a client is disconnected.
140 * Frees our resources associated with that client.
143 * @param client identification of the client
146 client_disconnect_notification (void *cls,
147 struct GNUNET_SERVER_Client *client)
149 struct NamecacheClient *nc;
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "Client %p disconnected\n",
156 if (NULL == (nc = GNUNET_SERVER_client_get_user_context (client, struct NamecacheClient)))
158 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
164 * Add a client to our list of active clients, if it is not yet
167 * @param client client to add
168 * @return internal namecache client structure for this client
170 static struct NamecacheClient *
171 client_lookup (struct GNUNET_SERVER_Client *client)
173 struct NamecacheClient *nc;
175 nc = GNUNET_SERVER_client_get_user_context (client, struct NamecacheClient);
178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
179 "Client %p connected\n",
181 nc = GNUNET_new (struct NamecacheClient);
183 GNUNET_SERVER_notification_context_add (snc, client);
184 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
185 GNUNET_SERVER_client_set_user_context (client, nc);
191 * Context for name lookups passed from #handle_lookup_block to
192 * #handle_lookup_block_it as closure
194 struct LookupBlockContext
197 * The client to send the response to
199 struct NamecacheClient *nc;
202 * Operation id for the name lookup
210 * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
212 * @param cls a `struct LookupNameContext *` with information about the request
213 * @param block the block
216 handle_lookup_block_it (void *cls,
217 const struct GNUNET_GNSRECORD_Block *block)
219 struct LookupBlockContext *lnc = cls;
220 struct LookupBlockResponseMessage *r;
223 esize = ntohl (block->purpose.size)
224 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
225 - sizeof (struct GNUNET_TIME_AbsoluteNBO);
226 r = GNUNET_malloc (sizeof (struct LookupBlockResponseMessage) + esize);
227 r->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
228 r->gns_header.header.size = htons (sizeof (struct LookupBlockResponseMessage) + esize);
229 r->gns_header.r_id = htonl (lnc->request_id);
230 r->expire = block->expiration_time;
231 r->signature = block->signature;
232 r->derived_key = block->derived_key;
233 memcpy (&r[1], &block[1], esize);
234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
235 "Sending `%s' message with expiration time %s\n",
236 "NAMECACHE_LOOKUP_BLOCK_RESPONSE",
237 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (r->expire)));
238 GNUNET_SERVER_notification_context_unicast (snc,
240 &r->gns_header.header,
247 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
250 * @param client client sending the message
251 * @param message message of type 'struct LookupNameMessage'
254 handle_lookup_block (void *cls,
255 struct GNUNET_SERVER_Client *client,
256 const struct GNUNET_MessageHeader *message)
258 const struct LookupBlockMessage *ln_msg;
259 struct LookupBlockContext lnc;
260 struct NamecacheClient *nc;
261 struct LookupBlockResponseMessage zir_end;
264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265 "Received `%s' message\n",
266 "NAMECACHE_LOOKUP_BLOCK");
267 nc = client_lookup(client);
268 ln_msg = (const struct LookupBlockMessage *) message;
269 lnc.request_id = ntohl (ln_msg->gns_header.r_id);
272 (ret = GSN_database->lookup_block (GSN_database->cls,
274 &handle_lookup_block_it, &lnc)))
276 /* internal error (in database plugin); might be best to just hang up on
277 plugin rather than to signal that there are 'no' results, which
278 might also be false... */
280 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
285 /* no records match at all, generate empty response */
286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
287 "Sending empty `%s' message\n",
288 "NAMECACHE_LOOKUP_BLOCK_RESPONSE");
289 memset (&zir_end, 0, sizeof (zir_end));
290 zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
291 zir_end.gns_header.header.size = htons (sizeof (struct LookupBlockResponseMessage));
292 zir_end.gns_header.r_id = ln_msg->gns_header.r_id;
293 GNUNET_SERVER_notification_context_unicast (snc,
295 &zir_end.gns_header.header,
299 GNUNET_SERVER_receive_done (client, GNUNET_OK);
304 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
307 * @param client client sending the message
308 * @param message message of type 'struct BlockCacheMessage'
311 handle_block_cache (void *cls,
312 struct GNUNET_SERVER_Client *client,
313 const struct GNUNET_MessageHeader *message)
315 struct NamecacheClient *nc;
316 const struct BlockCacheMessage *rp_msg;
317 struct BlockCacheResponseMessage rpr_msg;
318 struct GNUNET_GNSRECORD_Block *block;
322 nc = client_lookup (client);
323 if (ntohs (message->size) < sizeof (struct BlockCacheMessage))
326 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
329 rp_msg = (const struct BlockCacheMessage *) message;
330 esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
331 block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + esize);
332 block->signature = rp_msg->signature;
333 block->derived_key = rp_msg->derived_key;
334 block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
335 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
337 block->expiration_time = rp_msg->expire;
338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
339 "Received `%s' message with expiration time %s\n",
340 "NAMECACHE_BLOCK_CACHE",
341 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (block->expiration_time)));
342 memcpy (&block[1], &rp_msg[1], esize);
343 res = GSN_database->cache_block (GSN_database->cls,
347 rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
348 rpr_msg.gns_header.header.size = htons (sizeof (struct BlockCacheResponseMessage));
349 rpr_msg.gns_header.r_id = rp_msg->gns_header.r_id;
350 rpr_msg.op_result = htonl (res);
351 GNUNET_SERVER_notification_context_unicast (snc,
353 &rpr_msg.gns_header.header,
355 GNUNET_SERVER_receive_done (client, GNUNET_OK);
360 * Process namecache requests.
363 * @param server the initialized server
364 * @param cfg configuration to use
367 run (void *cls, struct GNUNET_SERVER_Handle *server,
368 const struct GNUNET_CONFIGURATION_Handle *cfg)
370 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
371 {&handle_lookup_block, NULL,
372 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK, sizeof (struct LookupBlockMessage)},
373 {&handle_block_cache, NULL,
374 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE, 0},
379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namecache service\n");
381 monitor_nc = GNUNET_SERVER_notification_context_create (server, 1);
383 /* Loading database plugin */
385 GNUNET_CONFIGURATION_get_value_string (cfg, "namecache", "database",
387 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
389 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namecache_%s", database);
390 GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
391 GNUNET_free (database);
392 if (NULL == GSN_database)
394 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
395 "Could not load database backend `%s'\n",
397 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
401 /* Configuring server handles */
402 GNUNET_SERVER_add_handlers (server, handlers);
403 snc = GNUNET_SERVER_notification_context_create (server, 16);
404 GNUNET_SERVER_disconnect_notify (server,
405 &client_disconnect_notification,
407 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
413 * The main function for the template service.
415 * @param argc number of arguments from the command line
416 * @param argv command line arguments
417 * @return 0 ok, 1 on error
420 main (int argc, char *const *argv)
423 GNUNET_SERVICE_run (argc, argv, "namecache",
424 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
427 /* end of gnunet-service-namecache.c */