src: for every AGPL3.0 file, add SPDX identifier.
[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      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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_statistics_service.h"
31 #include "gnunet_namecache_service.h"
32 #include "gnunet_namecache_plugin.h"
33 #include "gnunet_signatures.h"
34 #include "namecache.h"
35
36 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
37
38
39 /**
40  * A namecache client
41  */
42 struct NamecacheClient
43 {
44
45   /**
46    * The client
47    */
48   struct GNUNET_SERVICE_Client *client;
49
50   /**
51    * The message queue to talk to @e client.
52    */
53   struct GNUNET_MQ_Handle *mq;
54
55 };
56
57
58 /**
59  * Configuration handle.
60  */
61 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
62
63 /**
64  * Handle to the statistics service
65  */
66 static struct GNUNET_STATISTICS_Handle *statistics;
67
68 /**
69  * Database handle
70  */
71 static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
72
73 /**
74  * Name of the database plugin
75  */
76 static char *db_lib_name;
77
78
79 /**
80  * Task run during shutdown.
81  *
82  * @param cls unused
83  */
84 static void
85 cleanup_task (void *cls)
86 {
87   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
88               "Stopping namecache service\n");
89   GNUNET_break (NULL ==
90                 GNUNET_PLUGIN_unload (db_lib_name,
91                                       GSN_database));
92   GNUNET_free (db_lib_name);
93   db_lib_name = NULL;
94   if (NULL != statistics)
95   {
96     GNUNET_STATISTICS_destroy (statistics,
97                                GNUNET_NO);
98     statistics = NULL;
99   }
100 }
101
102
103 /**
104  * Called whenever a client is disconnected.
105  * Frees our resources associated with that client.
106  *
107  * @param cls closure
108  * @param client identification of the client
109  * @param app_ctx the `struct NamecacheClient` for this @a client
110  */
111 static void
112 client_disconnect_cb (void *cls,
113                       struct GNUNET_SERVICE_Client *client,
114                       void *app_ctx)
115 {
116   struct NamecacheClient *nc = app_ctx;
117
118   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
119               "Client %p disconnected\n",
120               client);
121   GNUNET_free (nc);
122 }
123
124
125 /**
126  * Add a client to our list of active clients.
127  *
128  * @param cls NULL
129  * @param client client to add
130  * @param mq queue to talk to @a client
131  * @return internal namecache client structure for this client
132  */
133 static void *
134 client_connect_cb (void *cls,
135                    struct GNUNET_SERVICE_Client *client,
136                    struct GNUNET_MQ_Handle *mq)
137 {
138   struct NamecacheClient *nc;
139
140   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
141               "Client %p connected\n",
142               client);
143   nc = GNUNET_new (struct NamecacheClient);
144   nc->client = client;
145   nc->mq = mq;
146   return nc;
147 }
148
149
150 /**
151  * Context for name lookups passed from #handle_lookup_block to
152  * #handle_lookup_block_it as closure
153  */
154 struct LookupBlockContext
155 {
156   /**
157    * The client to send the response to
158    */
159   struct NamecacheClient *nc;
160
161   /**
162    * Operation id for the name lookup
163    */
164   uint32_t request_id;
165   
166   /**
167    * Lookup status
168    */
169   int status;
170 };
171
172
173 /**
174  * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
175  *
176  * @param cls a `struct LookupNameContext *` with information about the request
177  * @param block the block
178  */
179 static void
180 handle_lookup_block_it (void *cls,
181                         const struct GNUNET_GNSRECORD_Block *block)
182 {
183   struct LookupBlockContext *lnc = cls;
184   struct GNUNET_MQ_Envelope *env;
185   struct LookupBlockResponseMessage *r;
186   size_t esize;
187   size_t bsize;
188
189   bsize = ntohl (block->purpose.size);
190   if (bsize < 
191       (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO)))
192   {
193     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
194                 "Malformed block.");
195     lnc->status = GNUNET_SYSERR;
196     return;
197   }
198   esize = ntohl (block->purpose.size)
199     - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
200     - sizeof (struct GNUNET_TIME_AbsoluteNBO);
201   env = GNUNET_MQ_msg_extra (r,
202                              esize,
203                              GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
204   r->gns_header.r_id = htonl (lnc->request_id);
205   r->expire = block->expiration_time;
206   r->signature = block->signature;
207   r->derived_key = block->derived_key;
208   GNUNET_memcpy (&r[1],
209                  &block[1],
210                  esize);
211   GNUNET_STATISTICS_update (statistics,
212                             "blocks found in cache",
213                             1,
214                             GNUNET_NO);
215   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
216               "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message with expiration time %s\n",
217               GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (r->expire)));
218   GNUNET_MQ_send (lnc->nc->mq,
219                   env);
220 }
221
222
223 /**
224  * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
225  *
226  * @param cls a `struct NamecacheClient *`
227  * @param the inbound message
228  */
229 static void
230 handle_lookup_block (void *cls,
231                      const struct LookupBlockMessage *ln_msg)
232 {
233   struct NamecacheClient *nc = cls;
234   struct GNUNET_MQ_Envelope *env;
235   struct LookupBlockContext lnc;
236   struct LookupBlockResponseMessage *zir_end;
237   int ret;
238
239   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
240               "Received NAMECACHE_LOOKUP_BLOCK message\n");
241   GNUNET_STATISTICS_update (statistics,
242                             "blocks looked up",
243                             1,
244                             GNUNET_NO);
245   lnc.request_id = ntohl (ln_msg->gns_header.r_id);
246   lnc.nc = nc;
247   lnc.status = GNUNET_OK;
248   if (GNUNET_SYSERR ==
249       (ret = GSN_database->lookup_block (GSN_database->cls,
250                                          &ln_msg->query,
251                                          &handle_lookup_block_it,
252                                          &lnc)))
253   {
254     /* internal error (in database plugin); might be best to just hang up on
255        plugin rather than to signal that there are 'no' results, which
256        might also be false... */
257     GNUNET_break (0);
258     GNUNET_SERVICE_client_drop (nc->client);
259     return;
260   }
261   if ((0 == ret) || (GNUNET_SYSERR == lnc.status))
262   {
263     /* no records match at all, generate empty response */
264     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265                 "Sending empty NAMECACHE_LOOKUP_BLOCK_RESPONSE message\n");
266     env = GNUNET_MQ_msg (zir_end,
267                          GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
268     zir_end->gns_header.r_id = ln_msg->gns_header.r_id;
269     GNUNET_MQ_send (nc->mq,
270                     env);
271   }
272   GNUNET_SERVICE_client_continue (nc->client);
273 }
274
275
276 /**
277  * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
278  *
279  * @param cls our `struct NamecacheClient`
280  * @param rp_msg message to process
281  * @return #GNUNET_OK (always fine)
282  */
283 static int
284 check_block_cache (void *cls,
285                    const struct BlockCacheMessage *rp_msg)
286 {
287   return GNUNET_OK;
288 }
289
290
291 /**
292  * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
293  *
294  * @param cls our `struct NamecacheClient`
295  * @param rp_msg message to process
296  */
297 static void
298 handle_block_cache (void *cls,
299                     const struct BlockCacheMessage *rp_msg)
300 {
301   struct NamecacheClient *nc = cls;
302   struct GNUNET_MQ_Envelope *env;
303   struct BlockCacheResponseMessage *rpr_msg;
304   struct GNUNET_GNSRECORD_Block *block;
305   size_t esize;
306   int res;
307
308   GNUNET_STATISTICS_update (statistics,
309                             "blocks cached",
310                             1,
311                             GNUNET_NO);
312   esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
313   block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + esize);
314   block->signature = rp_msg->signature;
315   block->derived_key = rp_msg->derived_key;
316   block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
317                                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
318                                esize);
319   block->expiration_time = rp_msg->expire;
320   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321               "Received NAMECACHE_BLOCK_CACHE message with expiration time %s\n",
322               GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (block->expiration_time)));
323   GNUNET_memcpy (&block[1],
324                  &rp_msg[1],
325                  esize);
326   res = GSN_database->cache_block (GSN_database->cls,
327                                    block);
328   GNUNET_free (block);
329   env = GNUNET_MQ_msg (rpr_msg,
330                        GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
331   rpr_msg->gns_header.r_id = rp_msg->gns_header.r_id;
332   rpr_msg->op_result = htonl (res);
333   GNUNET_MQ_send (nc->mq,
334                   env);
335   GNUNET_SERVICE_client_continue (nc->client);
336 }
337
338
339 /**
340  * Process namecache requests.
341  *
342  * @param cls closure
343  * @param cfg configuration to use
344  * @param service the initialized service
345  */
346 static void
347 run (void *cls,
348      const struct GNUNET_CONFIGURATION_Handle *cfg,
349      struct GNUNET_SERVICE_Handle *service)
350 {
351   char *database;
352
353   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354               "Starting namecache service\n");
355   GSN_cfg = cfg;
356
357   /* Loading database plugin */
358   if (GNUNET_OK !=
359       GNUNET_CONFIGURATION_get_value_string (cfg,
360                                              "namecache",
361                                              "database",
362                                              &database))
363     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
364                 "No database backend configured\n");
365
366   GNUNET_asprintf (&db_lib_name,
367                    "libgnunet_plugin_namecache_%s",
368                    database);
369   GSN_database = GNUNET_PLUGIN_load (db_lib_name,
370                                      (void *) GSN_cfg);
371   GNUNET_free (database);
372   if (NULL == GSN_database)
373   {
374     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
375                 "Could not load database backend `%s'\n",
376                 db_lib_name);
377     GNUNET_SCHEDULER_add_now (&cleanup_task,
378                               NULL);
379     return;
380   }
381   statistics = GNUNET_STATISTICS_create ("namecache",
382                                          cfg);
383
384   /* Configuring server handles */
385   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
386                                  NULL);
387 }
388
389
390 /**
391  * Define "main" method using service macro.
392  */
393 GNUNET_SERVICE_MAIN
394 ("namecache",
395  GNUNET_SERVICE_OPTION_NONE,
396  &run,
397  &client_connect_cb,
398  &client_disconnect_cb,
399  NULL,
400  GNUNET_MQ_hd_fixed_size (lookup_block,
401                           GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
402                           struct LookupBlockMessage,
403                           NULL),
404  GNUNET_MQ_hd_var_size (block_cache,
405                         GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
406                         struct BlockCacheMessage,
407                         NULL),
408  GNUNET_MQ_handler_end ());
409
410
411 /* end of gnunet-service-namecache.c */