- communication
[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
97   for (nc = client_head; nc != NULL; nc = nc->next)
98   {
99     for (no = nc->op_head; no != NULL; no = no->next)
100     {
101       GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
102       GNUNET_free (no);
103     }
104   }
105
106   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
107   GNUNET_free (nc);
108
109   GNUNET_SERVER_notification_context_destroy (snc);
110   snc = NULL;
111
112   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
113   GNUNET_free (db_lib_name);
114 }
115
116 static struct GNUNET_NAMESTORE_Client *
117 client_lookup (struct GNUNET_SERVER_Client *client)
118 {
119   struct GNUNET_NAMESTORE_Client * nc;
120
121   GNUNET_assert (NULL != client);
122
123   for (nc = client_head; nc != NULL; nc = nc->next)
124   {
125     if (client == nc->client)
126       break;
127   }
128   return nc;
129 }
130
131
132 /**
133  * Called whenever a client is disconnected.  Frees our
134  * resources associated with that client.
135  *
136  * @param cls closure
137  * @param client identification of the client
138  */
139 static void
140 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
141 {
142   struct GNUNET_NAMESTORE_Operation * no;
143   struct GNUNET_NAMESTORE_Client * nc;
144   if (NULL == client)
145     return;
146
147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected \n", client);
148
149   nc = client_lookup (client);
150
151   if ((NULL == client) || (NULL == nc))
152     return;
153
154   for (no = nc->op_head; no != NULL; no = no->next)
155   {
156     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
157     GNUNET_free (no);
158   }
159
160   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
161   GNUNET_free (nc);
162 }
163
164 static void handle_start (void *cls,
165                           struct GNUNET_SERVER_Client * client,
166                           const struct GNUNET_MessageHeader * message)
167 {
168   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
169
170   struct GNUNET_NAMESTORE_Client * nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client));
171   nc->client = client;
172   GNUNET_SERVER_notification_context_add (snc, client);
173   GNUNET_CONTAINER_DLL_insert(client_head, client_tail, nc);
174
175   GNUNET_SERVER_receive_done (client, GNUNET_OK);
176 }
177
178 static void handle_lookup_name (void *cls,
179                           struct GNUNET_SERVER_Client * client,
180                           const struct GNUNET_MessageHeader * message)
181 {
182   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_LOOKUP_NAME");
183
184   struct GNUNET_NAMESTORE_Client *nc;
185   uint32_t id = 0;
186   size_t r_size = 0;
187
188   nc = client_lookup(client);
189   if (nc == NULL)
190   {
191     GNUNET_break_op (0);
192     GNUNET_SERVER_receive_done (client, GNUNET_OK);
193     return;
194   }
195
196   struct LookupNameMessage * ln_msg = (struct LookupNameMessage *) message;
197   id = ntohl (ln_msg->op_id);
198
199   /* do the actual lookup */
200
201   /* send response */
202   struct LookupNameResponseMessage lnr_msg;
203   r_size = sizeof (struct LookupNameResponseMessage);
204
205   lnr_msg.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
206   lnr_msg.header.size = ntohs (r_size);
207   lnr_msg.op_id = htonl (id);
208
209   GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &lnr_msg, GNUNET_NO);
210   GNUNET_SERVER_receive_done (client, GNUNET_OK);
211 }
212
213
214 /**
215  * Process template requests.
216  *
217  * @param cls closure
218  * @param server the initialized server
219  * @param cfg configuration to use
220  */
221 static void
222 run (void *cls, struct GNUNET_SERVER_Handle *server,
223      const struct GNUNET_CONFIGURATION_Handle *cfg)
224 {
225   char * database;
226
227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
228
229   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
230     {&handle_start, NULL,
231      GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
232     {&handle_lookup_name, NULL,
233      GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, sizeof (struct LookupNameMessage)},
234     {NULL, NULL, 0, 0}
235   };
236
237   GSN_cfg = cfg;
238
239   /* Loading database plugin */
240   if (GNUNET_OK !=
241       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
242                                              &database))
243     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
244
245   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
246   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
247   if (GSN_database == NULL)
248     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load database backend `%s'\n",
249         db_lib_name);
250   GNUNET_free (database);
251
252   /* Configuring server handles */
253   GNUNET_SERVER_add_handlers (server, handlers);
254   snc = GNUNET_SERVER_notification_context_create (server, 16);
255   GNUNET_SERVER_disconnect_notify (server,
256                                    &client_disconnect_notification,
257                                    NULL);
258
259   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
260                                 NULL);
261
262 }
263
264
265 /**
266  * The main function for the template service.
267  *
268  * @param argc number of arguments from the command line
269  * @param argv command line arguments
270  * @return 0 ok, 1 on error
271  */
272 int
273 main (int argc, char *const *argv)
274 {
275   return (GNUNET_OK ==
276           GNUNET_SERVICE_run (argc, argv, "namestore",
277                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
278 }
279
280 /* end of gnunet-service-namestore.c */