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 a status code to the client.
97 * @param client receiver of the response
98 * @param code status code
99 * @param msg optional error message (can be NULL)
102 transmit_status (struct GNUNET_SERVER_Client *client,
106 struct StatusMessage *sm;
109 slen = (msg == NULL) ? 0 : strlen(msg) + 1;
110 sm = GNUNET_malloc (sizeof(struct StatusMessage) + slen);
111 sm->header.size = htons(sizeof(struct StatusMessage) + slen);
112 sm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_STATUS);
113 sm->status = htonl(code);
114 memcpy (&sm[1], msg, slen);
115 transmit (client, &sm->header);
121 * Function that will transmit the given datastore entry
124 * @param cls closure, pointer to the client (of type GNUNET_SERVER_Client).
125 * @param key key for the content
126 * @param size number of bytes in data
127 * @param data content stored
128 * @param type type of the content
129 * @param priority priority of the content
130 * @param anonymity anonymity-level for the content
131 * @param expiration expiration time for the content
132 * @param uid unique identifier for the datum;
133 * maybe 0 if no unique identifier is available
135 * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue,
136 * GNUNET_NO to delete the item and continue (if supported)
139 transmit_item (void *cls,
140 const GNUNET_HashCode * key,
146 struct GNUNET_TIME_Absolute
147 expiration, unsigned long long uid)
149 struct GNUNET_SERVER_Client *client = cls;
150 struct GNUNET_MessageHeader end;
151 struct DataMessage *dm;
155 /* transmit 'DATA_END' */
156 end.size = htons(sizeof(struct GNUNET_MessageHeader));
157 end.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END);
158 transmit (client, &end);
161 dm = GNUNET_malloc (sizeof(struct DataMessage) + size);
162 dm->header.size = htons(sizeof(struct DataMessage) + size);
163 dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_DATA);
165 dm->size = htonl(size);
166 dm->type = htonl(type);
167 dm->priority = htonl(priority);
168 dm->anonymity = htonl(anonymity);
169 dm->expiration = GNUNET_TIME_absolute_hton(expiration);
170 dm->uid = GNUNET_htonll(uid);
172 memcpy (&dm[1], data, size);
173 transmit (client, &dm->header);
180 * Handle RESERVE-message.
183 * @param client identification of the client
184 * @param message the actual message
187 handle_reserve (void *cls,
188 struct GNUNET_SERVER_Client *client,
189 const struct GNUNET_MessageHeader *message)
191 transmit_status (client, GNUNET_SYSERR, "not implemented");
192 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
197 * Handle RELEASE_RESERVE-message.
200 * @param client identification of the client
201 * @param message the actual message
204 handle_release_reserve (void *cls,
205 struct GNUNET_SERVER_Client *client,
206 const struct GNUNET_MessageHeader *message)
208 transmit_status (client, GNUNET_SYSERR, "not implemented");
209 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
214 * Check that the given message is a valid data message.
216 * @return NULL if the message is not well-formed, otherwise the message
218 static const struct DataMessage *
219 check_data (const struct GNUNET_MessageHeader *message)
223 const struct DataMessage *dm;
225 size = ntohs(message->size);
226 if (size < sizeof(struct DataMessage))
231 dm = (const struct DataMessage *) message;
232 dsize = ntohl(dm->size);
233 if (size != dsize + sizeof(struct DataMessage))
238 if (ntohl(dm->type) == 0)
248 * Handle PUT-message.
251 * @param client identification of the client
252 * @param message the actual message
255 handle_put (void *cls,
256 struct GNUNET_SERVER_Client *client,
257 const struct GNUNET_MessageHeader *message)
259 const struct DataMessage *dm = check_data (message);
267 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
270 rid = ntohl(dm->rid);
273 /* FIXME: find reservation, update remaining! */
276 ret = plugin->api->put (plugin->api->cls,
282 ntohl(dm->anonymity),
283 GNUNET_TIME_absolute_ntoh(dm->expiration),
285 transmit_status (client, ret, msg);
286 GNUNET_free_non_null (msg);
287 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
292 * Handle GET-message.
295 * @param client identification of the client
296 * @param message the actual message
299 handle_get (void *cls,
300 struct GNUNET_SERVER_Client *client,
301 const struct GNUNET_MessageHeader *message)
303 const struct GetMessage *msg;
306 size = ntohs(message->size);
307 if ( (size != sizeof(struct GetMessage)) &&
308 (size != sizeof(struct GetMessage) - sizeof(GNUNET_HashCode)) )
311 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
314 msg = (const struct GetMessage*) message;
315 plugin->api->get (plugin->api->cls,
316 ((size == sizeof(struct GetMessage)) ? &msg->key : NULL),
321 GNUNET_SERVER_receive_done (client, GNUNET_OK);
326 * Handle UPDATE-message.
329 * @param client identification of the client
330 * @param message the actual message
333 handle_update (void *cls,
334 struct GNUNET_SERVER_Client *client,
335 const struct GNUNET_MessageHeader *message)
337 const struct UpdateMessage *msg;
341 msg = (const struct UpdateMessage*) message;
343 ret = plugin->api->update (plugin->api->cls,
344 GNUNET_ntohll(msg->uid),
345 (int32_t) ntohl(msg->priority),
346 GNUNET_TIME_absolute_ntoh(msg->expiration),
348 transmit_status (client, ret, emsg);
349 GNUNET_free_non_null (emsg);
350 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
355 * Handle GET_RANDOM-message.
358 * @param client identification of the client
359 * @param message the actual message
362 handle_get_random (void *cls,
363 struct GNUNET_SERVER_Client *client,
364 const struct GNUNET_MessageHeader *message)
366 plugin->api->iter_migration_order (plugin->api->cls,
370 GNUNET_SERVER_receive_done (client, GNUNET_OK);
375 * Callback function that will cause the item that is passed
376 * in to be deleted (by returning GNUNET_NO).
379 remove_callback (void *cls,
380 const GNUNET_HashCode * key,
386 struct GNUNET_TIME_Absolute
387 expiration, unsigned long long uid)
396 * Handle REMOVE-message.
399 * @param client identification of the client
400 * @param message the actual message
403 handle_remove (void *cls,
404 struct GNUNET_SERVER_Client *client,
405 const struct GNUNET_MessageHeader *message)
407 const struct DataMessage *dm = check_data (message);
408 GNUNET_HashCode vhash;
414 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
418 GNUNET_CRYPTO_hash (&dm[1],
421 plugin->api->get (plugin->api->cls,
427 if (GNUNET_YES == found)
428 transmit_status (client, GNUNET_OK, NULL);
430 transmit_status (client, GNUNET_SYSERR, _("Content not found"));
431 GNUNET_SERVER_receive_done (client, GNUNET_OK);
436 * Handle DROP-message.
439 * @param client identification of the client
440 * @param message the actual message
443 handle_drop (void *cls,
444 struct GNUNET_SERVER_Client *client,
445 const struct GNUNET_MessageHeader *message)
447 plugin->api->drop (plugin->api->cls);
448 GNUNET_SERVER_receive_done (client, GNUNET_OK);
453 * List of handlers for the messages understood by this
456 static struct GNUNET_SERVER_MessageHandler handlers[] = {
457 {&handle_reserve, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE,
458 sizeof(struct ReserveMessage) },
459 {&handle_release_reserve, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE,
460 sizeof(struct ReleaseReserveMessage) },
461 {&handle_put, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_PUT, 0 },
462 {&handle_update, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE,
463 sizeof (struct UpdateMessage) },
464 {&handle_get, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET, 0 },
465 {&handle_get_random, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET_RANDOM,
466 sizeof(struct GNUNET_MessageHeader) },
467 {&handle_remove, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE, 0 },
468 {&handle_drop, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_DROP,
469 sizeof(struct GNUNET_MessageHeader) },
476 * Load the datastore plugin.
478 static struct DatastorePlugin *
479 load_plugin (struct GNUNET_CONFIGURATION_Handle *cfg,
480 struct GNUNET_SCHEDULER_Handle *sched)
482 struct DatastorePlugin *ret;
487 GNUNET_CONFIGURATION_get_value_string (cfg,
488 "DATASTORE", "DATABASE", &name))
490 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
491 _("No `%s' specified for `%s' in configuration!\n"),
496 ret = GNUNET_malloc (sizeof(struct DatastorePlugin));
498 ret->env.sched = sched;
499 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
500 _("Loading `%s' datastore plugin\n"), name);
501 GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
502 ret->short_name = GNUNET_strdup (name);
503 ret->lib_name = libname;
504 ret->api = GNUNET_PLUGIN_load (libname, &ret->env);
505 if (ret->api == NULL)
507 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
508 _("Failed to load datastore plugin for `%s'\n"), name);
509 GNUNET_free (ret->short_name);
510 GNUNET_free (libname);
519 * Function called when the service shuts
520 * down. Unloads our datastore plugin.
523 * @param cfg configuration to use
526 unload_plugin (struct DatastorePlugin *plug)
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
530 "Datastore service is unloading plugin...\n");
532 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
533 GNUNET_free (plug->lib_name);
534 GNUNET_free (plug->short_name);
540 * Last task run during shutdown. Disconnects us from
541 * the transport and core.
544 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
546 unload_plugin (plugin);
552 * Process datastore requests.
555 * @param sched scheduler to use
556 * @param server the initialized server
557 * @param cfg configuration to use
561 struct GNUNET_SCHEDULER_Handle *sched,
562 struct GNUNET_SERVER_Handle *server,
563 struct GNUNET_CONFIGURATION_Handle *cfg)
565 plugin = load_plugin (cfg, sched);
568 GNUNET_SERVER_add_handlers (server, handlers);
569 GNUNET_SCHEDULER_add_delayed (sched,
571 GNUNET_SCHEDULER_PRIORITY_IDLE,
572 GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
573 GNUNET_TIME_UNIT_FOREVER_REL,
574 &cleaning_task, NULL);
579 * The main function for the datastore service.
581 * @param argc number of arguments from the command line
582 * @param argv command line arguments
583 * @return 0 ok, 1 on error
586 main (int argc, char *const *argv)
591 GNUNET_SERVICE_run (argc,
593 "datastore", &run, NULL, NULL, NULL)) ? 0 : 1;
598 /* end of gnunet-service-datastore.c */