glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / namecache / gnunet-service-namecache.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2013 GNUnet e.V.
4
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.
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      Affero General Public License for more details.
14 */
15
16 /**
17  * @file namecache/gnunet-service-namecache.c
18  * @brief namecache for the GNUnet naming system
19  * @author Matthias Wachs
20  * @author Christian Grothoff
21  */
22 #include "platform.h"
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"
29
30 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
31
32
33 /**
34  * A namecache client
35  */
36 struct NamecacheClient
37 {
38
39   /**
40    * The client
41    */
42   struct GNUNET_SERVICE_Client *client;
43
44   /**
45    * The message queue to talk to @e client.
46    */
47   struct GNUNET_MQ_Handle *mq;
48
49 };
50
51
52 /**
53  * Configuration handle.
54  */
55 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
56
57 /**
58  * Database handle
59  */
60 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
61
62 /**
63  * Name of the database plugin
64  */
65 static char *db_lib_name;
66
67
68 /**
69  * Task run during shutdown.
70  *
71  * @param cls unused
72  */
73 static void
74 cleanup_task (void *cls)
75 {
76   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77               "Stopping namecache service\n");
78   GNUNET_break (NULL ==
79                 GNUNET_PLUGIN_unload (db_lib_name,
80                                       GSN_database));
81   GNUNET_free (db_lib_name);
82   db_lib_name = NULL;
83 }
84
85
86 /**
87  * Called whenever a client is disconnected.
88  * Frees our resources associated with that client.
89  *
90  * @param cls closure
91  * @param client identification of the client
92  * @param app_ctx the `struct NamecacheClient` for this @a client
93  */
94 static void
95 client_disconnect_cb (void *cls,
96                       struct GNUNET_SERVICE_Client *client,
97                       void *app_ctx)
98 {
99   struct NamecacheClient *nc = app_ctx;
100
101   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
102               "Client %p disconnected\n",
103               client);
104   GNUNET_free (nc);
105 }
106
107
108 /**
109  * Add a client to our list of active clients.
110  *
111  * @param cls NULL
112  * @param client client to add
113  * @param mq queue to talk to @a client
114  * @return internal namecache client structure for this client
115  */
116 static void *
117 client_connect_cb (void *cls,
118                    struct GNUNET_SERVICE_Client *client,
119                    struct GNUNET_MQ_Handle *mq)
120 {
121   struct NamecacheClient *nc;
122
123   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
124               "Client %p connected\n",
125               client);
126   nc = GNUNET_new (struct NamecacheClient);
127   nc->client = client;
128   nc->mq = mq;
129   return nc;
130 }
131
132
133 /**
134  * Context for name lookups passed from #handle_lookup_block to
135  * #handle_lookup_block_it as closure
136  */
137 struct LookupBlockContext
138 {
139   /**
140    * The client to send the response to
141    */
142   struct NamecacheClient *nc;
143
144   /**
145    * Operation id for the name lookup
146    */
147   uint32_t request_id;
148
149 };
150
151
152 /**
153  * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
154  *
155  * @param cls a `struct LookupNameContext *` with information about the request
156  * @param block the block
157  */
158 static void
159 handle_lookup_block_it (void *cls,
160                         const struct GNUNET_GNSRECORD_Block *block)
161 {
162   struct LookupBlockContext *lnc = cls;
163   struct GNUNET_MQ_Envelope *env;
164   struct LookupBlockResponseMessage *r;
165   size_t esize;
166
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,
171                              esize,
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],
178                  &block[1],
179                  esize);
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,
184                   env);
185 }
186
187
188 /**
189  * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
190  *
191  * @param cls a `struct NamecacheClient *`
192  * @param the inbound message
193  */
194 static void
195 handle_lookup_block (void *cls,
196                      const struct LookupBlockMessage *ln_msg)
197 {
198   struct NamecacheClient *nc = cls;
199   struct GNUNET_MQ_Envelope *env;
200   struct LookupBlockContext lnc;
201   struct LookupBlockResponseMessage *zir_end;
202   int ret;
203
204   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205               "Received NAMECACHE_LOOKUP_BLOCK message\n");
206
207   lnc.request_id = ntohl (ln_msg->gns_header.r_id);
208   lnc.nc = nc;
209   if (GNUNET_SYSERR ==
210       (ret = GSN_database->lookup_block (GSN_database->cls,
211                                          &ln_msg->query,
212                                          &handle_lookup_block_it,
213                                          &lnc)))
214   {
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... */
218     GNUNET_break (0);
219     GNUNET_SERVICE_client_drop (nc->client);
220     return;
221   }
222   if (0 == ret)
223   {
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,
231                     env);
232   }
233   GNUNET_SERVICE_client_continue (nc->client);
234 }
235
236
237 /**
238  * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
239  *
240  * @param cls our `struct NamecacheClient`
241  * @param rp_msg message to process
242  * @return #GNUNET_OK (always fine)
243  */
244 static int
245 check_block_cache (void *cls,
246                    const struct BlockCacheMessage *rp_msg)
247 {
248   return GNUNET_OK;
249 }
250
251
252 /**
253  * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
254  *
255  * @param cls our `struct NamecacheClient`
256  * @param rp_msg message to process
257  */
258 static void
259 handle_block_cache (void *cls,
260                     const struct BlockCacheMessage *rp_msg)
261 {
262   struct NamecacheClient *nc = cls;
263   struct GNUNET_MQ_Envelope *env;
264   struct BlockCacheResponseMessage *rpr_msg;
265   struct GNUNET_GNSRECORD_Block *block;
266   size_t esize;
267   int res;
268
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) +
275                                esize);
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],
281                  &rp_msg[1],
282                  esize);
283   res = GSN_database->cache_block (GSN_database->cls,
284                                    block);
285   GNUNET_free (block);
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,
291                   env);
292   GNUNET_SERVICE_client_continue (nc->client);
293 }
294
295
296 /**
297  * Process namecache requests.
298  *
299  * @param cls closure
300  * @param cfg configuration to use
301  * @param service the initialized service
302  */
303 static void
304 run (void *cls,
305      const struct GNUNET_CONFIGURATION_Handle *cfg,
306      struct GNUNET_SERVICE_Handle *service)
307 {
308   char *database;
309
310   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
311               "Starting namecache service\n");
312   GSN_cfg = cfg;
313
314   /* Loading database plugin */
315   if (GNUNET_OK !=
316       GNUNET_CONFIGURATION_get_value_string (cfg,
317                                              "namecache",
318                                              "database",
319                                              &database))
320     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
321                 "No database backend configured\n");
322
323   GNUNET_asprintf (&db_lib_name,
324                    "libgnunet_plugin_namecache_%s",
325                    database);
326   GSN_database = GNUNET_PLUGIN_load (db_lib_name,
327                                      (void *) GSN_cfg);
328   GNUNET_free (database);
329   if (NULL == GSN_database)
330   {
331     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
332                 "Could not load database backend `%s'\n",
333                 db_lib_name);
334     GNUNET_SCHEDULER_add_now (&cleanup_task,
335                               NULL);
336     return;
337   }
338
339   /* Configuring server handles */
340   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
341                                  NULL);
342 }
343
344
345 /**
346  * Define "main" method using service macro.
347  */
348 GNUNET_SERVICE_MAIN
349 ("namecache",
350  GNUNET_SERVICE_OPTION_NONE,
351  &run,
352  &client_connect_cb,
353  &client_disconnect_cb,
354  NULL,
355  GNUNET_MQ_hd_fixed_size (lookup_block,
356                           GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
357                           struct LookupBlockMessage,
358                           NULL),
359  GNUNET_MQ_hd_var_size (block_cache,
360                         GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
361                         struct BlockCacheMessage,
362                         NULL),
363  GNUNET_MQ_handler_end ());
364
365
366 /* end of gnunet-service-namecache.c */