2 This file is part of GNUnet
3 (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
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 2, or (at your
8 option) any later version.
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.
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.
22 * @file datastore/gnunet-service-datastore.c
23 * @brief Management for the datastore for files stored on a GNUnet node
24 * @author Christian Grothoff
27 * 1) transmit and transmit flow-control (when do we signal client 'success'?
28 * ALSO: async transmit will need to address ref-counting issues on client!
29 * 2) efficient "update" for client to raise priority / expiration
30 * (not possible with current datastore API, but plugin API has support!);
31 * [ maybe integrate desired priority/expiration updates directly
32 * with 'GET' request? ]
33 * 3) semantics of "PUT" (plugin) if entry exists (should likely
34 * be similar to "UPDATE" (need to specify in PLUGIN API!)
35 * 4) quota management code!
36 * 5) add bloomfilter for efficiency!
40 #include "gnunet_util_lib.h"
41 #include "gnunet_protocols.h"
42 #include "plugin_datastore.h"
43 #include "datastore.h"
47 * Our datastore plugin.
49 struct DatastorePlugin
53 * API of the transport as returned by the plugin's
54 * initialization function.
56 struct GNUNET_DATASTORE_PluginFunctions *api;
59 * Short name for the plugin (i.e. "sqlite").
64 * Name of the library (i.e. "gnunet_plugin_datastore_sqlite").
69 * Environment this transport service is using
72 struct GNUNET_DATASTORE_PluginEnvironment env;
78 * Our datastore plugin (NULL if not available).
80 static struct DatastorePlugin *plugin;
84 * Transmit the given message to the client.
87 transmit (struct GNUNET_SERVER_Client *client,
88 const struct GNUNET_MessageHeader *msg)
95 * Transmit the size of the current datastore to the client.
98 transmit_size (struct GNUNET_SERVER_Client *client)
100 struct SizeMessage sm;
102 sm.header.size = htons(sizeof(struct SizeMessage));
103 sm.header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_SIZE);
104 sm.reserved = htonl(0);
105 sm.size = GNUNET_htonll(plugin->api->get_size (plugin->api->cls));
106 transmit (client, &sm.header);
111 * Function that will transmit the given datastore entry
114 * @param cls closure, pointer to the client (of type GNUNET_SERVER_Client).
115 * @param key key for the content
116 * @param size number of bytes in data
117 * @param data content stored
118 * @param type type of the content
119 * @param priority priority of the content
120 * @param anonymity anonymity-level for the content
121 * @param expiration expiration time for the content
122 * @param uid unique identifier for the datum;
123 * maybe 0 if no unique identifier is available
125 * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue,
126 * GNUNET_NO to delete the item and continue (if supported)
129 transmit_item (void *cls,
130 const GNUNET_HashCode * key,
136 struct GNUNET_TIME_Absolute
137 expiration, unsigned long long uid)
139 struct GNUNET_SERVER_Client *client = cls;
140 struct GNUNET_MessageHeader end;
141 struct DataMessage *dm;
145 /* transmit 'DATA_END' */
146 end.size = htons(sizeof(struct GNUNET_MessageHeader));
147 end.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END);
148 transmit (client, &end);
151 /* FIXME: make use of 'uid' for efficient priority/expiration update! */
152 dm = GNUNET_malloc (sizeof(struct DataMessage) + size);
153 dm->header.size = htons(sizeof(struct DataMessage) + size);
154 dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_DATA);
155 dm->reserved = htonl(0);
156 dm->size = htonl(size);
157 dm->type = htonl(type);
158 dm->priority = htonl(priority);
159 dm->anonymity = htonl(anonymity);
160 dm->expiration = GNUNET_TIME_absolute_hton(expiration);
162 memcpy (&dm[1], data, size);
163 transmit (client, &dm->header);
170 * Handle INIT-message.
173 * @param client identification of the client
174 * @param message the actual message
177 handle_init (void *cls,
178 struct GNUNET_SERVER_Client *client,
179 const struct GNUNET_MessageHeader *message)
181 transmit_size (client);
182 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
187 * Check that the given message is a valid data message.
189 * @return NULL if the message is not well-formed, otherwise the message
191 static const struct DataMessage *
192 check_data (const struct GNUNET_MessageHeader *message)
196 const struct DataMessage *dm;
198 size = ntohs(message->size);
199 if (size < sizeof(struct DataMessage))
204 dm = (const struct DataMessage *) message;
205 dsize = ntohl(dm->size);
206 if (size != dsize + sizeof(struct DataMessage))
211 if ( (ntohl(dm->type) == 0) ||
212 (ntohl(dm->reserved) != 0) )
222 * Handle PUT-message.
225 * @param client identification of the client
226 * @param message the actual message
229 handle_put (void *cls,
230 struct GNUNET_SERVER_Client *client,
231 const struct GNUNET_MessageHeader *message)
233 const struct DataMessage *dm = check_data (message);
237 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
240 plugin->api->put (plugin->api->cls,
246 ntohl(dm->anonymity),
247 GNUNET_TIME_absolute_ntoh(dm->expiration));
248 transmit_size (client);
249 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
254 * Handle GET-message.
257 * @param client identification of the client
258 * @param message the actual message
261 handle_get (void *cls,
262 struct GNUNET_SERVER_Client *client,
263 const struct GNUNET_MessageHeader *message)
265 const struct GetMessage *msg;
268 size = ntohs(message->size);
269 if ( (size != sizeof(struct GetMessage)) &&
270 (size != sizeof(struct GetMessage) - sizeof(GNUNET_HashCode)) )
273 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
276 msg = (const struct GetMessage*) message;
277 plugin->api->get (plugin->api->cls,
278 ((size == sizeof(struct GetMessage)) ? &msg->key : NULL),
283 GNUNET_SERVER_receive_done (client, GNUNET_OK);
288 * Handle GET_RANDOM-message.
291 * @param client identification of the client
292 * @param message the actual message
295 handle_get_random (void *cls,
296 struct GNUNET_SERVER_Client *client,
297 const struct GNUNET_MessageHeader *message)
299 plugin->api->iter_migration_order (plugin->api->cls,
303 GNUNET_SERVER_receive_done (client, GNUNET_OK);
308 * Callback function that will cause the item that is passed
309 * in to be deleted (by returning GNUNET_NO).
312 remove_callback (void *cls,
313 const GNUNET_HashCode * key,
319 struct GNUNET_TIME_Absolute
320 expiration, unsigned long long uid)
327 * Handle REMOVE-message.
330 * @param client identification of the client
331 * @param message the actual message
334 handle_remove (void *cls,
335 struct GNUNET_SERVER_Client *client,
336 const struct GNUNET_MessageHeader *message)
338 const struct DataMessage *dm = check_data (message);
339 GNUNET_HashCode vhash;
344 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
347 GNUNET_CRYPTO_hash (&dm[1],
350 plugin->api->get (plugin->api->cls,
356 transmit_size (client);
357 GNUNET_SERVER_receive_done (client, GNUNET_OK);
362 * Handle DROP-message.
365 * @param client identification of the client
366 * @param message the actual message
369 handle_drop (void *cls,
370 struct GNUNET_SERVER_Client *client,
371 const struct GNUNET_MessageHeader *message)
373 plugin->api->drop (plugin->api->cls);
374 GNUNET_SERVER_receive_done (client, GNUNET_OK);
379 * List of handlers for the messages understood by this
382 static struct GNUNET_SERVER_MessageHandler handlers[] = {
383 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_INIT,
384 sizeof(struct GNUNET_MessageHeader) },
385 {&handle_put, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_PUT, 0 },
386 {&handle_get, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET, 0 },
387 {&handle_get_random, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET_RANDOM,
388 sizeof(struct GNUNET_MessageHeader) },
389 {&handle_remove, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE, 0 },
390 {&handle_drop, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_DROP,
391 sizeof(struct GNUNET_MessageHeader) },
398 * Load the datastore plugin.
400 static struct DatastorePlugin *
401 load_plugin (struct GNUNET_CONFIGURATION_Handle *cfg,
402 struct GNUNET_SCHEDULER_Handle *sched)
404 struct DatastorePlugin *ret;
409 GNUNET_CONFIGURATION_get_value_string (cfg,
410 "DATASTORE", "DATABASE", &name))
412 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
413 _("No `%s' specified for `%s' in configuration!\n"),
418 ret = GNUNET_malloc (sizeof(struct DatastorePlugin));
420 ret->env.sched = sched;
421 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
422 _("Loading `%s' datastore plugin\n"), name);
423 GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
424 ret->short_name = GNUNET_strdup (name);
425 ret->lib_name = libname;
426 ret->api = GNUNET_PLUGIN_load (libname, &ret->env);
427 if (ret->api == NULL)
429 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
430 _("Failed to load datastore plugin for `%s'\n"), name);
431 GNUNET_free (ret->short_name);
432 GNUNET_free (libname);
441 * Function called when the service shuts
442 * down. Unloads our datastore plugin.
445 * @param cfg configuration to use
448 unload_plugin (struct DatastorePlugin *plug)
451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452 "Datastore service is unloading plugin...\n");
454 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
455 GNUNET_free (plug->lib_name);
456 GNUNET_free (plug->short_name);
462 * Last task run during shutdown. Disconnects us from
463 * the transport and core.
466 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
468 unload_plugin (plugin);
474 * Process datastore requests.
477 * @param sched scheduler to use
478 * @param server the initialized server
479 * @param cfg configuration to use
483 struct GNUNET_SCHEDULER_Handle *sched,
484 struct GNUNET_SERVER_Handle *server,
485 struct GNUNET_CONFIGURATION_Handle *cfg)
487 plugin = load_plugin (cfg, sched);
490 GNUNET_SERVER_add_handlers (server, handlers);
491 GNUNET_SCHEDULER_add_delayed (sched,
493 GNUNET_SCHEDULER_PRIORITY_IDLE,
494 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
495 GNUNET_TIME_UNIT_FOREVER_REL,
496 &cleaning_task, NULL);
501 * The main function for the datastore service.
503 * @param argc number of arguments from the command line
504 * @param argv command line arguments
505 * @return 0 ok, 1 on error
508 main (int argc, char *const *argv)
513 GNUNET_SERVICE_run (argc,
515 "datastore", &run, NULL, NULL, NULL)) ? 0 : 1;
520 /* end of gnunet-service-datastore.c */