- minor changes, TODO, debug message
[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
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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  */
41 struct NamecacheClient
42 {
43
44   /**
45    * The client
46    */
47   struct GNUNET_SERVICE_Client *client;
48
49   /**
50    * The message queue to talk to @e client.
51    */
52   struct GNUNET_MQ_Handle *mq;
53   
54 };
55
56
57 /**
58  * Configuration handle.
59  */
60 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
61
62 /**
63  * Database handle
64  */
65 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
66
67 /**
68  * Name of the database plugin
69  */
70 static char *db_lib_name;
71
72
73 /**
74  * Task run during shutdown.
75  *
76  * @param cls unused
77  */
78 static void
79 cleanup_task (void *cls)
80 {
81   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
82               "Stopping namecache service\n");
83   GNUNET_break (NULL ==
84                 GNUNET_PLUGIN_unload (db_lib_name,
85                                       GSN_database));
86   GNUNET_free (db_lib_name);
87   db_lib_name = NULL;
88 }
89
90
91 /**
92  * Called whenever a client is disconnected.
93  * Frees our resources associated with that client.
94  *
95  * @param cls closure
96  * @param client identification of the client
97  * @param app_ctx the `struct NamecacheClient` for this @a client
98  */
99 static void
100 client_disconnect_cb (void *cls,
101                       struct GNUNET_SERVICE_Client *client,
102                       void *app_ctx)
103 {
104   struct NamecacheClient *nc = app_ctx;
105
106   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
107               "Client %p disconnected\n",
108               client);
109   GNUNET_free (nc);
110 }
111
112
113 /**
114  * Add a client to our list of active clients.
115  *
116  * @param cls NULL
117  * @param client client to add
118  * @param mq queue to talk to @a client
119  * @return internal namecache client structure for this client
120  */
121 static void *
122 client_connect_cb (void *cls,
123                    struct GNUNET_SERVICE_Client *client,
124                    struct GNUNET_MQ_Handle *mq)
125 {
126   struct NamecacheClient *nc;
127
128   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
129               "Client %p connected\n",
130               client);
131   nc = GNUNET_new (struct NamecacheClient);
132   nc->client = client;
133   nc->mq = mq;
134   return nc;
135 }
136
137
138 /**
139  * Context for name lookups passed from #handle_lookup_block to
140  * #handle_lookup_block_it as closure
141  */
142 struct LookupBlockContext
143 {
144   /**
145    * The client to send the response to
146    */
147   struct NamecacheClient *nc;
148
149   /**
150    * Operation id for the name lookup
151    */
152   uint32_t request_id;
153
154 };
155
156
157 /**
158  * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
159  *
160  * @param cls a `struct LookupNameContext *` with information about the request
161  * @param block the block
162  */
163 static void
164 handle_lookup_block_it (void *cls,
165                         const struct GNUNET_GNSRECORD_Block *block)
166 {
167   struct LookupBlockContext *lnc = cls;
168   struct GNUNET_MQ_Envelope *env;
169   struct LookupBlockResponseMessage *r;
170   size_t esize;
171
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,
176                              esize,
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],
183                  &block[1],
184                  esize);
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,
189                   env);
190 }
191
192
193 /**
194  * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
195  *
196  * @param cls a `struct NamecacheClient *`
197  * @param the inbound message
198  */
199 static void
200 handle_lookup_block (void *cls,
201                      const struct LookupBlockMessage *ln_msg)
202 {
203   struct NamecacheClient *nc = cls;
204   struct GNUNET_MQ_Envelope *env;
205   struct LookupBlockContext lnc;
206   struct LookupBlockResponseMessage *zir_end;
207   int ret;
208
209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210               "Received NAMECACHE_LOOKUP_BLOCK message\n");
211   
212   lnc.request_id = ntohl (ln_msg->gns_header.r_id);
213   lnc.nc = nc;
214   if (GNUNET_SYSERR ==
215       (ret = GSN_database->lookup_block (GSN_database->cls,
216                                          &ln_msg->query,
217                                          &handle_lookup_block_it,
218                                          &lnc)))
219   {
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... */
223     GNUNET_break (0);
224     GNUNET_SERVICE_client_drop (nc->client);
225     return;
226   }
227   if (0 == ret)
228   {
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,
236                     env);
237   }
238   GNUNET_SERVICE_client_continue (nc->client);
239 }
240
241
242 /**
243  * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
244  *
245  * @param cls our `struct NamecacheClient`
246  * @param rp_msg message to process
247  * @return #GNUNET_OK (always fine)
248  */
249 static int
250 check_block_cache (void *cls,
251                    const struct BlockCacheMessage *rp_msg)
252 {
253   return GNUNET_OK;
254 }
255
256
257 /**
258  * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
259  *
260  * @param cls our `struct NamecacheClient`
261  * @param rp_msg message to process
262  */
263 static void
264 handle_block_cache (void *cls,
265                     const struct BlockCacheMessage *rp_msg)
266 {
267   struct NamecacheClient *nc = cls;
268   struct GNUNET_MQ_Envelope *env;
269   struct BlockCacheResponseMessage *rpr_msg;
270   struct GNUNET_GNSRECORD_Block *block;
271   size_t esize;
272   int res;
273
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) +
280                                esize);
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],
286                  &rp_msg[1],
287                  esize);
288   res = GSN_database->cache_block (GSN_database->cls,
289                                    block);
290   GNUNET_free (block);
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,
296                   env);
297   GNUNET_SERVICE_client_continue (nc->client);
298 }
299
300
301 /**
302  * Process namecache requests.
303  *
304  * @param cls closure
305  * @param cfg configuration to use
306  * @param service the initialized service
307  */
308 static void
309 run (void *cls, 
310      const struct GNUNET_CONFIGURATION_Handle *cfg,
311      struct GNUNET_SERVICE_Handle *service)
312 {
313   char *database;
314
315   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316               "Starting namecache service\n");
317   GSN_cfg = cfg;
318
319   /* Loading database plugin */
320   if (GNUNET_OK !=
321       GNUNET_CONFIGURATION_get_value_string (cfg,
322                                              "namecache",
323                                              "database",
324                                              &database))
325     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
326                 "No database backend configured\n");
327
328   GNUNET_asprintf (&db_lib_name,
329                    "libgnunet_plugin_namecache_%s",
330                    database);
331   GSN_database = GNUNET_PLUGIN_load (db_lib_name,
332                                      (void *) GSN_cfg);
333   GNUNET_free (database);
334   if (NULL == GSN_database)
335   {
336     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
337                 "Could not load database backend `%s'\n",
338                 db_lib_name);
339     GNUNET_SCHEDULER_add_now (&cleanup_task,
340                               NULL);
341     return;
342   }
343
344   /* Configuring server handles */
345   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
346                                  NULL);
347 }
348
349
350 /**
351  * Define "main" method using service macro.
352  */
353 GNUNET_SERVICE_MAIN
354 ("namecache",
355  GNUNET_SERVICE_OPTION_NONE,
356  &run,
357  &client_connect_cb,
358  &client_disconnect_cb,
359  NULL,
360  GNUNET_MQ_hd_fixed_size (lookup_block,
361                           GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
362                           struct LookupBlockMessage,
363                           NULL),
364  GNUNET_MQ_hd_var_size (block_cache,
365                         GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
366                         struct BlockCacheMessage,
367                         NULL),
368  GNUNET_MQ_handler_end ());
369
370
371 /* end of gnunet-service-namecache.c */