aboutsummaryrefslogtreecommitdiff
path: root/src/namecache/gnunet-service-namecache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namecache/gnunet-service-namecache.c')
-rw-r--r--src/namecache/gnunet-service-namecache.c429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/namecache/gnunet-service-namecache.c b/src/namecache/gnunet-service-namecache.c
new file mode 100644
index 000000000..832f02b45
--- /dev/null
+++ b/src/namecache/gnunet-service-namecache.c
@@ -0,0 +1,429 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file namecache/gnunet-service-namecache.c
23 * @brief namecache for the GNUnet naming system
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
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"
34
35#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
36
37
38/**
39 * A namecache client
40 */
41struct NamecacheClient;
42
43
44/**
45 * A namecache client
46 */
47struct NamecacheClient
48{
49 /**
50 * Next element in the DLL
51 */
52 struct NamecacheClient *next;
53
54 /**
55 * Previous element in the DLL
56 */
57 struct NamecacheClient *prev;
58
59 /**
60 * The client
61 */
62 struct GNUNET_SERVER_Client *client;
63
64};
65
66
67/**
68 * Configuration handle.
69 */
70static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
71
72/**
73 * Database handle
74 */
75static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
76
77/**
78 * Name of the database plugin
79 */
80static char *db_lib_name;
81
82/**
83 * Our notification context.
84 */
85static struct GNUNET_SERVER_NotificationContext *snc;
86
87/**
88 * Head of the Client DLL
89 */
90static struct NamecacheClient *client_head;
91
92/**
93 * Tail of the Client DLL
94 */
95static struct NamecacheClient *client_tail;
96
97/**
98 * Notification context shared by all monitors.
99 */
100static struct GNUNET_SERVER_NotificationContext *monitor_nc;
101
102
103
104/**
105 * Task run during shutdown.
106 *
107 * @param cls unused
108 * @param tc unused
109 */
110static void
111cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
112{
113 struct NamecacheClient *nc;
114
115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
116 "Stopping namecache service\n");
117 if (NULL != snc)
118 {
119 GNUNET_SERVER_notification_context_destroy (snc);
120 snc = NULL;
121 }
122 while (NULL != (nc = client_head))
123 {
124 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
125 GNUNET_SERVER_client_set_user_context (nc->client, NULL);
126 GNUNET_free (nc);
127 }
128 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
129 GNUNET_free (db_lib_name);
130 db_lib_name = NULL;
131 if (NULL != monitor_nc)
132 {
133 GNUNET_SERVER_notification_context_destroy (monitor_nc);
134 monitor_nc = NULL;
135 }
136}
137
138
139/**
140 * Called whenever a client is disconnected.
141 * Frees our resources associated with that client.
142 *
143 * @param cls closure
144 * @param client identification of the client
145 */
146static void
147client_disconnect_notification (void *cls,
148 struct GNUNET_SERVER_Client *client)
149{
150 struct NamecacheClient *nc;
151
152 if (NULL == client)
153 return;
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155 "Client %p disconnected\n",
156 client);
157 if (NULL == (nc = GNUNET_SERVER_client_get_user_context (client, struct NamecacheClient)))
158 return;
159 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
160 GNUNET_free (nc);
161}
162
163
164/**
165 * Add a client to our list of active clients, if it is not yet
166 * in there.
167 *
168 * @param client client to add
169 * @return internal namecache client structure for this client
170 */
171static struct NamecacheClient *
172client_lookup (struct GNUNET_SERVER_Client *client)
173{
174 struct NamecacheClient *nc;
175
176 nc = GNUNET_SERVER_client_get_user_context (client, struct NamecacheClient);
177 if (NULL != nc)
178 return nc;
179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
180 "Client %p connected\n",
181 client);
182 nc = GNUNET_new (struct NamecacheClient);
183 nc->client = client;
184 GNUNET_SERVER_notification_context_add (snc, client);
185 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
186 GNUNET_SERVER_client_set_user_context (client, nc);
187 return nc;
188}
189
190
191/**
192 * Context for name lookups passed from #handle_lookup_block to
193 * #handle_lookup_block_it as closure
194 */
195struct LookupBlockContext
196{
197 /**
198 * The client to send the response to
199 */
200 struct NamecacheClient *nc;
201
202 /**
203 * Operation id for the name lookup
204 */
205 uint32_t request_id;
206
207};
208
209
210/**
211 * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
212 *
213 * @param cls a `struct LookupNameContext *` with information about the request
214 * @param block the block
215 */
216static void
217handle_lookup_block_it (void *cls,
218 const struct GNUNET_NAMESTORE_Block *block)
219{
220 struct LookupBlockContext *lnc = cls;
221 struct LookupBlockResponseMessage *r;
222 size_t esize;
223
224 esize = ntohl (block->purpose.size)
225 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
226 - sizeof (struct GNUNET_TIME_AbsoluteNBO);
227 r = GNUNET_malloc (sizeof (struct LookupBlockResponseMessage) + esize);
228 r->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
229 r->gns_header.header.size = htons (sizeof (struct LookupBlockResponseMessage) + esize);
230 r->gns_header.r_id = htonl (lnc->request_id);
231 r->expire = block->expiration_time;
232 r->signature = block->signature;
233 r->derived_key = block->derived_key;
234 memcpy (&r[1], &block[1], esize);
235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236 "Sending `%s' message with expiration time %s\n",
237 "NAMECACHE_LOOKUP_BLOCK_RESPONSE",
238 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (r->expire)));
239 GNUNET_SERVER_notification_context_unicast (snc,
240 lnc->nc->client,
241 &r->gns_header.header,
242 GNUNET_NO);
243 GNUNET_free (r);
244}
245
246
247/**
248 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
249 *
250 * @param cls unused
251 * @param client client sending the message
252 * @param message message of type 'struct LookupNameMessage'
253 */
254static void
255handle_lookup_block (void *cls,
256 struct GNUNET_SERVER_Client *client,
257 const struct GNUNET_MessageHeader *message)
258{
259 const struct LookupBlockMessage *ln_msg;
260 struct LookupBlockContext lnc;
261 struct NamecacheClient *nc;
262 struct LookupBlockResponseMessage zir_end;
263 int ret;
264
265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
266 "Received `%s' message\n",
267 "NAMECACHE_LOOKUP_BLOCK");
268 nc = client_lookup(client);
269 ln_msg = (const struct LookupBlockMessage *) message;
270 lnc.request_id = ntohl (ln_msg->gns_header.r_id);
271 lnc.nc = nc;
272 if (GNUNET_SYSERR ==
273 (ret = GSN_database->lookup_block (GSN_database->cls,
274 &ln_msg->query,
275 &handle_lookup_block_it, &lnc)))
276 {
277 /* internal error (in database plugin); might be best to just hang up on
278 plugin rather than to signal that there are 'no' results, which
279 might also be false... */
280 GNUNET_break (0);
281 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
282 return;
283 }
284 if (0 == ret)
285 {
286 /* no records match at all, generate empty response */
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Sending empty `%s' message\n",
289 "NAMECACHE_LOOKUP_BLOCK_RESPONSE");
290 memset (&zir_end, 0, sizeof (zir_end));
291 zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
292 zir_end.gns_header.header.size = htons (sizeof (struct LookupBlockResponseMessage));
293 zir_end.gns_header.r_id = ln_msg->gns_header.r_id;
294 GNUNET_SERVER_notification_context_unicast (snc,
295 client,
296 &zir_end.gns_header.header,
297 GNUNET_NO);
298
299 }
300 GNUNET_SERVER_receive_done (client, GNUNET_OK);
301}
302
303
304/**
305 * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
306 *
307 * @param cls unused
308 * @param client client sending the message
309 * @param message message of type 'struct BlockCacheMessage'
310 */
311static void
312handle_block_cache (void *cls,
313 struct GNUNET_SERVER_Client *client,
314 const struct GNUNET_MessageHeader *message)
315{
316 struct NamecacheClient *nc;
317 const struct BlockCacheMessage *rp_msg;
318 struct BlockCacheResponseMessage rpr_msg;
319 struct GNUNET_NAMESTORE_Block *block;
320 size_t esize;
321 int res;
322
323 nc = client_lookup (client);
324 if (ntohs (message->size) < sizeof (struct BlockCacheMessage))
325 {
326 GNUNET_break (0);
327 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
328 return;
329 }
330 rp_msg = (const struct BlockCacheMessage *) message;
331 esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
332 block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) + esize);
333 block->signature = rp_msg->signature;
334 block->derived_key = rp_msg->derived_key;
335 block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
336 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
337 esize);
338 block->expiration_time = rp_msg->expire;
339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
340 "Received `%s' message with expiration time %s\n",
341 "NAMECACHE_BLOCK_CACHE",
342 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (block->expiration_time)));
343 memcpy (&block[1], &rp_msg[1], esize);
344 res = GSN_database->cache_block (GSN_database->cls,
345 block);
346 GNUNET_free (block);
347
348 rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
349 rpr_msg.gns_header.header.size = htons (sizeof (struct BlockCacheResponseMessage));
350 rpr_msg.gns_header.r_id = rp_msg->gns_header.r_id;
351 rpr_msg.op_result = htonl (res);
352 GNUNET_SERVER_notification_context_unicast (snc,
353 nc->client,
354 &rpr_msg.gns_header.header,
355 GNUNET_NO);
356 GNUNET_SERVER_receive_done (client, GNUNET_OK);
357}
358
359
360/**
361 * Process namecache requests.
362 *
363 * @param cls closure
364 * @param server the initialized server
365 * @param cfg configuration to use
366 */
367static void
368run (void *cls, struct GNUNET_SERVER_Handle *server,
369 const struct GNUNET_CONFIGURATION_Handle *cfg)
370{
371 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
372 {&handle_lookup_block, NULL,
373 GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK, sizeof (struct LookupBlockMessage)},
374 {&handle_block_cache, NULL,
375 GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE, 0},
376 {NULL, NULL, 0, 0}
377 };
378 char *database;
379
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namecache service\n");
381 GSN_cfg = cfg;
382 monitor_nc = GNUNET_SERVER_notification_context_create (server, 1);
383
384 /* Loading database plugin */
385 if (GNUNET_OK !=
386 GNUNET_CONFIGURATION_get_value_string (cfg, "namecache", "database",
387 &database))
388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
389
390 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namecache_%s", database);
391 GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
392 GNUNET_free (database);
393 if (NULL == GSN_database)
394 {
395 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
396 "Could not load database backend `%s'\n",
397 db_lib_name);
398 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
399 return;
400 }
401
402 /* Configuring server handles */
403 GNUNET_SERVER_add_handlers (server, handlers);
404 snc = GNUNET_SERVER_notification_context_create (server, 16);
405 GNUNET_SERVER_disconnect_notify (server,
406 &client_disconnect_notification,
407 NULL);
408 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
409 NULL);
410}
411
412
413/**
414 * The main function for the template service.
415 *
416 * @param argc number of arguments from the command line
417 * @param argv command line arguments
418 * @return 0 ok, 1 on error
419 */
420int
421main (int argc, char *const *argv)
422{
423 return (GNUNET_OK ==
424 GNUNET_SERVICE_run (argc, argv, "namecache",
425 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
426}
427
428/* end of gnunet-service-namecache.c */
429