- lookup API send recv
[oweals/gnunet.git] / src / namestore / gnunet-service-namestore.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 namestore/gnunet-service-namestore.c
23  * @brief namestore for the GNUnet naming system
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_getopt_lib.h"
28 #include "gnunet_service_lib.h"
29 #include "gnunet_namestore_service.h"
30 #include "gnunet_namestore_plugin.h"
31 #include "namestore.h"
32
33
34
35 /**
36  * A namestore operation.
37  */
38 struct GNUNET_NAMESTORE_Operation
39 {
40   struct GNUNET_NAMESTORE_Operation *next;
41   struct GNUNET_NAMESTORE_Operation *prev;
42
43   uint64_t op_id;
44
45   char *data; /*stub data pointer*/
46 };
47
48
49 /**
50  * A namestore client
51  */
52 struct GNUNET_NAMESTORE_Client
53 {
54   struct GNUNET_NAMESTORE_Client *next;
55   struct GNUNET_NAMESTORE_Client *prev;
56
57   struct GNUNET_SERVER_Client * client;
58
59   struct GNUNET_NAMESTORE_Operation *op_head;
60   struct GNUNET_NAMESTORE_Operation *op_tail;
61 };
62
63
64
65 /**
66  * Configuration handle.
67  */
68 const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
69
70 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
71
72 /**
73  * Our notification context.
74  */
75 static struct GNUNET_SERVER_NotificationContext *snc;
76
77 static char *db_lib_name;
78
79 static struct GNUNET_NAMESTORE_Client *client_head;
80 static struct GNUNET_NAMESTORE_Client *client_tail;
81
82
83 /**
84  * Task run during shutdown.
85  *
86  * @param cls unused
87  * @param tc unused
88  */
89 static void
90 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
91 {
92   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
93
94   struct GNUNET_NAMESTORE_Operation * no;
95   struct GNUNET_NAMESTORE_Client * nc;
96   struct GNUNET_NAMESTORE_Client * next;
97
98   for (nc = client_head; nc != NULL; nc = next)
99   {
100     next = nc->next;
101     for (no = nc->op_head; no != NULL; no = no->next)
102     {
103       GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
104       GNUNET_free (no);
105     }
106
107     GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
108     GNUNET_free (nc);
109
110   }
111
112   GNUNET_SERVER_notification_context_destroy (snc);
113   snc = NULL;
114
115   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
116   GNUNET_free (db_lib_name);
117 }
118
119 static struct GNUNET_NAMESTORE_Client *
120 client_lookup (struct GNUNET_SERVER_Client *client)
121 {
122   struct GNUNET_NAMESTORE_Client * nc;
123
124   GNUNET_assert (NULL != client);
125
126   for (nc = client_head; nc != NULL; nc = nc->next)
127   {
128     if (client == nc->client)
129       break;
130   }
131   return nc;
132 }
133
134
135 /**
136  * Called whenever a client is disconnected.  Frees our
137  * resources associated with that client.
138  *
139  * @param cls closure
140  * @param client identification of the client
141  */
142 static void
143 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
144 {
145   struct GNUNET_NAMESTORE_Operation * no;
146   struct GNUNET_NAMESTORE_Client * nc;
147   if (NULL == client)
148     return;
149
150   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected \n", client);
151
152   nc = client_lookup (client);
153
154   if ((NULL == client) || (NULL == nc))
155     return;
156
157   for (no = nc->op_head; no != NULL; no = no->next)
158   {
159     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
160     GNUNET_free (no);
161   }
162
163   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
164   GNUNET_free (nc);
165 }
166
167 static void handle_start (void *cls,
168                           struct GNUNET_SERVER_Client * client,
169                           const struct GNUNET_MessageHeader * message)
170 {
171   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
172
173   struct GNUNET_NAMESTORE_Client * nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client));
174   nc->client = client;
175   GNUNET_SERVER_notification_context_add (snc, client);
176   GNUNET_CONTAINER_DLL_insert(client_head, client_tail, nc);
177
178   GNUNET_SERVER_receive_done (client, GNUNET_OK);
179 }
180
181 struct LookupNameContext
182 {
183   struct GNUNET_NAMESTORE_Client *nc;
184   uint32_t id;
185   uint32_t record_type;
186 };
187
188
189 static void
190 handle_lookup_name_it (void *cls,
191     const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
192     struct GNUNET_TIME_Absolute expire,
193     const char *name,
194     unsigned int rd_count,
195     const struct GNUNET_NAMESTORE_RecordData *rd,
196     const struct GNUNET_CRYPTO_RsaSignature *signature)
197 {
198   /* send response */
199   struct LookupNameContext *lnc = cls;
200   struct LookupNameResponseMessage *lnr_msg;
201
202   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key_tmp;
203   struct GNUNET_NAMESTORE_RecordData * rd_tmp;
204   char *name_tmp;
205   struct GNUNET_CRYPTO_RsaSignature *signature_tmp;
206
207   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "NAMESTORE_LOOKUP_NAME_RESPONSE");
208
209   size_t r_size = 0;
210
211   size_t name_len = 0;
212   if (NULL != name)
213     name_len = strlen(name) + 1;
214
215   int copied_elements = 0;
216   int contains_signature = 0;
217   int c;
218
219   /* count records to copy */
220   if (rd_count != 0)
221   {
222     if (lnc->record_type != 0)
223     {
224       /* special record type needed */
225       for (c = 0; c < rd_count; c ++)
226         if (rd[c].record_type == lnc->record_type)
227           copied_elements++; /* found matching record */
228     }
229     else
230       copied_elements = rd_count;
231   }
232
233   if ((copied_elements == rd_count) && (signature != NULL))
234       contains_signature = GNUNET_YES;
235
236   r_size = sizeof (struct LookupNameResponseMessage) +
237            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
238            name_len +
239            copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData) +
240            contains_signature * sizeof (struct GNUNET_CRYPTO_RsaSignature);
241
242   lnr_msg = GNUNET_malloc (r_size);
243
244   lnr_msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
245   lnr_msg->header.size = ntohs (r_size);
246   lnr_msg->op_id = htonl (lnc->id);
247   lnr_msg->rc_count = htonl (copied_elements);
248   lnr_msg->name_len = htons (name_len);
249   lnr_msg->expire = GNUNET_TIME_absolute_hton(expire);
250   lnr_msg->contains_sig = htons (contains_signature);
251
252
253   zone_key_tmp =  (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) &lnr_msg[1];
254   name_tmp = (char *) &zone_key_tmp[1];
255   rd_tmp = (struct GNUNET_NAMESTORE_RecordData *) &name_tmp[name_len];
256   signature_tmp = (struct GNUNET_CRYPTO_RsaSignature *) &rd_tmp[copied_elements];
257
258   if (zone_key != NULL)
259     memcpy (zone_key_tmp, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
260   else
261   {
262     struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded dummy;
263     memset (&dummy, '0', sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
264     memcpy (zone_key_tmp, &dummy, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
265   }
266   memcpy (name_tmp, name, name_len);
267   /* copy records */
268   copied_elements = 0;
269   if (rd_count != 0)
270   {
271     if (lnc->record_type != 0)
272     {
273       /* special record type needed */
274       for (c = 0; c < rd_count; c ++)
275         if (rd[c].record_type == lnc->record_type)
276         {
277           /* found matching record */
278           memcpy (&rd_tmp[copied_elements], &rd[c], rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
279           copied_elements++;
280         }
281     }
282     else
283       memcpy (rd_tmp, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
284   }
285
286   if (GNUNET_YES == contains_signature)
287     memcpy (signature_tmp, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature));
288   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DONE `%s' message\n", "NAMESTORE_LOOKUP_NAME_RESPONSE");
289   GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client, (const struct GNUNET_MessageHeader *) lnr_msg, GNUNET_NO);
290
291   GNUNET_free (lnr_msg);
292 }
293
294 static void handle_lookup_name (void *cls,
295                           struct GNUNET_SERVER_Client * client,
296                           const struct GNUNET_MessageHeader * message)
297 {
298   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_LOOKUP_NAME");
299   struct LookupNameContext lnc;
300   struct GNUNET_NAMESTORE_Client *nc;
301   GNUNET_HashCode name_hash;
302   size_t name_len;
303   char * name;
304   uint32_t id = 0;
305   uint32_t type = 0;
306
307
308   if (ntohs (message->size) < sizeof (struct LookupNameMessage))
309   {
310     GNUNET_break_op (0);
311     GNUNET_SERVER_receive_done (client, GNUNET_OK);
312     return;
313   }
314
315   nc = client_lookup(client);
316   if (nc == NULL)
317   {
318     GNUNET_break_op (0);
319     GNUNET_SERVER_receive_done (client, GNUNET_OK);
320     return;
321   }
322
323   struct LookupNameMessage * ln_msg = (struct LookupNameMessage *) message;
324   id = ntohl (ln_msg->op_id);
325   name_len = ntohl (ln_msg->name_len);
326   type = ntohl (ln_msg->record_type);
327
328   if ((name_len == 0) || (name_len > 256))
329   {
330     GNUNET_break_op (0);
331     GNUNET_SERVER_receive_done (client, GNUNET_OK);
332     return;
333   }
334
335   name = GNUNET_malloc (name_len);
336   memcpy (name, &ln_msg[1], name_len);
337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up record for name `%s'\n", name);
338   GNUNET_CRYPTO_hash(name, name_len-1, &name_hash);
339   GNUNET_free (name);
340
341   /* do the actual lookup */
342   lnc.id = id;
343   lnc.nc = nc;
344   lnc.record_type = type;
345   GSN_database->iterate_records(GSN_database->cls, &ln_msg->zone, &ln_msg->zone, 0, &handle_lookup_name_it, &lnc);
346
347   GNUNET_SERVER_receive_done (client, GNUNET_OK);
348 }
349
350
351 /**
352  * Process template requests.
353  *
354  * @param cls closure
355  * @param server the initialized server
356  * @param cfg configuration to use
357  */
358 static void
359 run (void *cls, struct GNUNET_SERVER_Handle *server,
360      const struct GNUNET_CONFIGURATION_Handle *cfg)
361 {
362   char * database;
363
364   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
365
366   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
367     {&handle_start, NULL,
368      GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
369     {&handle_lookup_name, NULL,
370      GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
371     {NULL, NULL, 0, 0}
372   };
373
374   GSN_cfg = cfg;
375
376   /* Loading database plugin */
377   if (GNUNET_OK !=
378       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
379                                              &database))
380     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
381
382   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
383   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
384   if (GSN_database == NULL)
385     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load database backend `%s'\n",
386         db_lib_name);
387   GNUNET_free (database);
388
389   /* Configuring server handles */
390   GNUNET_SERVER_add_handlers (server, handlers);
391   snc = GNUNET_SERVER_notification_context_create (server, 16);
392   GNUNET_SERVER_disconnect_notify (server,
393                                    &client_disconnect_notification,
394                                    NULL);
395
396   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
397                                 NULL);
398
399 }
400
401
402 /**
403  * The main function for the template service.
404  *
405  * @param argc number of arguments from the command line
406  * @param argv command line arguments
407  * @return 0 ok, 1 on error
408  */
409 int
410 main (int argc, char *const *argv)
411 {
412   return (GNUNET_OK ==
413           GNUNET_SERVICE_run (argc, argv, "namestore",
414                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
415 }
416
417 /* end of gnunet-service-namestore.c */